xref: /freebsd/sys/dev/nctgpio/nctgpio.c (revision 0957b409)
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 		.chip_id	= 0xc453,
145 		.descr		= "Nuvoton NCT5104D (PC-Engines APU3)",
146 	},
147 };
148 
149 static void
150 write_cfg_reg_1(struct nct_softc *sc, uint8_t reg, uint8_t value)
151 {
152 	GPIO_ASSERT_LOCKED(sc);
153 	bus_write_1(sc->portres, 0, reg);
154 	NCT_BARRIER_WRITE(sc);
155 	bus_write_1(sc->portres, 1, value);
156 	NCT_BARRIER_WRITE(sc);
157 }
158 
159 static uint8_t
160 read_cfg_reg_1(struct nct_softc *sc, uint8_t reg)
161 {
162 	uint8_t value;
163 
164 	GPIO_ASSERT_LOCKED(sc);
165 	bus_write_1(sc->portres, 0, reg);
166 	NCT_BARRIER_READ_WRITE(sc);
167 	value = bus_read_1(sc->portres, 1);
168 	NCT_BARRIER_READ_WRITE(sc);
169 
170 	return (value);
171 }
172 
173 static uint16_t
174 read_cfg_reg_2(struct nct_softc *sc, uint8_t reg)
175 {
176 	uint16_t value;
177 
178 	value = read_cfg_reg_1(sc, reg) << 8;
179 	value |= read_cfg_reg_1(sc, reg + 1);
180 
181 	return (value);
182 }
183 
184 /*
185  * Enable extended function mode.
186  *
187  */
188 static void
189 ext_cfg_enter(struct nct_softc *sc)
190 {
191 	GPIO_ASSERT_LOCKED(sc);
192 	bus_write_1(sc->portres, 0, NCT_EXTFUNC_ENTER);
193 	NCT_BARRIER_WRITE(sc);
194 	bus_write_1(sc->portres, 0, NCT_EXTFUNC_ENTER);
195 	NCT_BARRIER_WRITE(sc);
196 }
197 
198 /*
199  * Disable extended function mode.
200  *
201  */
202 static void
203 ext_cfg_exit(struct nct_softc *sc)
204 {
205 	GPIO_ASSERT_LOCKED(sc);
206 	bus_write_1(sc->portres, 0, NCT_EXTFUNC_EXIT);
207 	NCT_BARRIER_WRITE(sc);
208 }
209 
210 /*
211  * Select a Logical Device.
212  */
213 static void
214 select_ldn(struct nct_softc *sc, uint8_t ldn)
215 {
216 	write_cfg_reg_1(sc, NCT_CR_LDN, ldn);
217 }
218 
219 /*
220  * Get the GPIO Input/Output register address
221  * for a pin.
222  */
223 static uint8_t
224 nct_ior_addr(uint32_t pin_num)
225 {
226 	uint8_t addr;
227 
228 	addr = NCT_LD7_GPIO0_IOR;
229 	if (pin_num > 7)
230 		addr = NCT_LD7_GPIO1_IOR;
231 
232 	return (addr);
233 }
234 
235 /*
236  * Get the GPIO Data register address for a pin.
237  */
238 static uint8_t
239 nct_dat_addr(uint32_t pin_num)
240 {
241 	uint8_t addr;
242 
243 	addr = NCT_LD7_GPIO0_DAT;
244 	if (pin_num > 7)
245 		addr = NCT_LD7_GPIO1_DAT;
246 
247 	return (addr);
248 }
249 
250 /*
251  * Get the GPIO Inversion register address
252  * for a pin.
253  */
254 static uint8_t
255 nct_inv_addr(uint32_t pin_num)
256 {
257 	uint8_t addr;
258 
259 	addr = NCT_LD7_GPIO0_INV;
260 	if (pin_num > 7)
261 		addr = NCT_LD7_GPIO1_INV;
262 
263 	return (addr);
264 }
265 
266 /*
267  * Get the GPIO Output Configuration/Mode
268  * register address for a pin.
269  */
270 static uint8_t
271 nct_outcfg_addr(uint32_t pin_num)
272 {
273 	uint8_t addr;
274 
275 	addr = NCT_LDF_GPIO0_OUTCFG;
276 	if (pin_num > 7)
277 		addr = NCT_LDF_GPIO1_OUTCFG;
278 
279 	return (addr);
280 }
281 
282 /*
283  * Set a pin to output mode.
284  */
285 static void
286 nct_set_pin_is_output(struct nct_softc *sc, uint32_t pin_num)
287 {
288 	uint8_t reg;
289 	uint8_t ior;
290 
291 	reg = nct_ior_addr(pin_num);
292 	select_ldn(sc, NCT_LDN_GPIO);
293 	ior = read_cfg_reg_1(sc, reg);
294 	ior &= ~(NCT_PIN_BIT(pin_num));
295 	write_cfg_reg_1(sc, reg, ior);
296 }
297 
298 /*
299  * Set a pin to input mode.
300  */
301 static void
302 nct_set_pin_is_input(struct nct_softc *sc, uint32_t pin_num)
303 {
304 	uint8_t reg;
305 	uint8_t ior;
306 
307 	reg = nct_ior_addr(pin_num);
308 	select_ldn(sc, NCT_LDN_GPIO);
309 	ior = read_cfg_reg_1(sc, reg);
310 	ior |= NCT_PIN_BIT(pin_num);
311 	write_cfg_reg_1(sc, reg, ior);
312 }
313 
314 /*
315  * Check whether a pin is configured as an input.
316  */
317 static bool
318 nct_pin_is_input(struct nct_softc *sc, uint32_t pin_num)
319 {
320 	uint8_t reg;
321 	uint8_t ior;
322 
323 	reg = nct_ior_addr(pin_num);
324 	select_ldn(sc, NCT_LDN_GPIO);
325 	ior = read_cfg_reg_1(sc, reg);
326 
327 	return (ior & NCT_PIN_BIT(pin_num));
328 }
329 
330 /*
331  * Write a value to an output pin.
332  */
333 static void
334 nct_write_pin(struct nct_softc *sc, uint32_t pin_num, uint8_t data)
335 {
336 	uint8_t reg;
337 	uint8_t value;
338 
339 	reg = nct_dat_addr(pin_num);
340 	select_ldn(sc, NCT_LDN_GPIO);
341 	value = read_cfg_reg_1(sc, reg);
342 	if (data)
343 		value |= NCT_PIN_BIT(pin_num);
344 	else
345 		value &= ~(NCT_PIN_BIT(pin_num));
346 
347 	write_cfg_reg_1(sc, reg, value);
348 }
349 
350 static bool
351 nct_read_pin(struct nct_softc *sc, uint32_t pin_num)
352 {
353 	uint8_t reg;
354 
355 	reg = nct_dat_addr(pin_num);
356 	select_ldn(sc, NCT_LDN_GPIO);
357 
358 	return (read_cfg_reg_1(sc, reg) & NCT_PIN_BIT(pin_num));
359 }
360 
361 static void
362 nct_set_pin_is_inverted(struct nct_softc *sc, uint32_t pin_num)
363 {
364 	uint8_t reg;
365 	uint8_t inv;
366 
367 	reg = nct_inv_addr(pin_num);
368 	select_ldn(sc, NCT_LDN_GPIO);
369 	inv = read_cfg_reg_1(sc, reg);
370 	inv |= (NCT_PIN_BIT(pin_num));
371 	write_cfg_reg_1(sc, reg, inv);
372 }
373 
374 static void
375 nct_set_pin_not_inverted(struct nct_softc *sc, uint32_t pin_num)
376 {
377 	uint8_t reg;
378 	uint8_t inv;
379 
380 	reg = nct_inv_addr(pin_num);
381 	select_ldn(sc, NCT_LDN_GPIO);
382 	inv = read_cfg_reg_1(sc, reg);
383 	inv &= ~(NCT_PIN_BIT(pin_num));
384 	write_cfg_reg_1(sc, reg, inv);
385 }
386 
387 static bool
388 nct_pin_is_inverted(struct nct_softc *sc, uint32_t pin_num)
389 {
390 	uint8_t reg;
391 	uint8_t inv;
392 
393 	reg = nct_inv_addr(pin_num);
394 	select_ldn(sc, NCT_LDN_GPIO);
395 	inv = read_cfg_reg_1(sc, reg);
396 
397 	return (inv & NCT_PIN_BIT(pin_num));
398 }
399 
400 static void
401 nct_set_pin_opendrain(struct nct_softc *sc, uint32_t pin_num)
402 {
403 	uint8_t reg;
404 	uint8_t outcfg;
405 
406 	reg = nct_outcfg_addr(pin_num);
407 	select_ldn(sc, NCT_LDN_GPIO_MODE);
408 	outcfg = read_cfg_reg_1(sc, reg);
409 	outcfg |= (NCT_PIN_BIT(pin_num));
410 	write_cfg_reg_1(sc, reg, outcfg);
411 }
412 
413 static void
414 nct_set_pin_pushpull(struct nct_softc *sc, uint32_t pin_num)
415 {
416 	uint8_t reg;
417 	uint8_t outcfg;
418 
419 	reg = nct_outcfg_addr(pin_num);
420 	select_ldn(sc, NCT_LDN_GPIO_MODE);
421 	outcfg = read_cfg_reg_1(sc, reg);
422 	outcfg &= ~(NCT_PIN_BIT(pin_num));
423 	write_cfg_reg_1(sc, reg, outcfg);
424 }
425 
426 static bool
427 nct_pin_is_opendrain(struct nct_softc *sc, uint32_t pin_num)
428 {
429 	uint8_t reg;
430 	uint8_t outcfg;
431 
432 	reg = nct_outcfg_addr(pin_num);
433 	select_ldn(sc, NCT_LDN_GPIO_MODE);
434 	outcfg = read_cfg_reg_1(sc, reg);
435 
436 	return (outcfg & NCT_PIN_BIT(pin_num));
437 }
438 
439 static void
440 nct_identify(driver_t *driver, device_t parent)
441 {
442 	if (device_find_child(parent, driver->name, 0) != NULL)
443 		return;
444 
445 	BUS_ADD_CHILD(parent, 0, driver->name, 0);
446 }
447 
448 static int
449 nct_probe(device_t dev)
450 {
451 	int i, j;
452 	int rc;
453 	struct nct_softc *sc;
454 	uint16_t chipid;
455 
456 	/* Make sure we do not claim some ISA PNP device. */
457 	if (isa_get_logicalid(dev) != 0)
458 		return (ENXIO);
459 
460 	sc = device_get_softc(dev);
461 
462 	for (i = 0; i < nitems(probe_addrs); i++) {
463 		sc->rid = 0;
464 		sc->portres = bus_alloc_resource(dev, SYS_RES_IOPORT, &sc->rid,
465 			probe_addrs[i], probe_addrs[i] + 1, 2, RF_ACTIVE);
466 		if (sc->portres == NULL)
467 			continue;
468 
469 		GPIO_LOCK_INIT(sc);
470 
471 		GPIO_ASSERT_UNLOCKED(sc);
472 		GPIO_LOCK(sc);
473 		ext_cfg_enter(sc);
474 		chipid = read_cfg_reg_2(sc, NCT_CR_CHIP_ID);
475 		ext_cfg_exit(sc);
476 		GPIO_UNLOCK(sc);
477 
478 		GPIO_LOCK_DESTROY(sc);
479 
480 		bus_release_resource(dev, SYS_RES_IOPORT, sc->rid, sc->portres);
481 		bus_delete_resource(dev, SYS_RES_IOPORT, sc->rid);
482 
483 		for (j = 0; j < nitems(nct_devs); j++) {
484 			if (chipid == nct_devs[j].chip_id) {
485 				rc = bus_set_resource(dev, SYS_RES_IOPORT, 0, probe_addrs[i], 2);
486 				if (rc != 0) {
487 					device_printf(dev, "bus_set_resource failed for address 0x%02X\n", probe_addrs[i]);
488 					continue;
489 				}
490 				device_set_desc(dev, nct_devs[j].descr);
491 				return (BUS_PROBE_DEFAULT);
492 			}
493 		}
494 	}
495 	return (ENXIO);
496 }
497 
498 static int
499 nct_attach(device_t dev)
500 {
501 	struct nct_softc *sc;
502 	int i;
503 
504 	sc = device_get_softc(dev);
505 
506 	sc->rid = 0;
507 	sc->portres = bus_alloc_resource(dev, SYS_RES_IOPORT, &sc->rid,
508 		0ul, ~0ul, 2, RF_ACTIVE);
509 	if (sc->portres == NULL) {
510 		device_printf(dev, "cannot allocate ioport\n");
511 		return (ENXIO);
512 	}
513 
514 	GPIO_LOCK_INIT(sc);
515 
516 	GPIO_ASSERT_UNLOCKED(sc);
517 	GPIO_LOCK(sc);
518 	ext_cfg_enter(sc);
519 	select_ldn(sc, NCT_LDN_GPIO);
520 	/* Enable gpio0 and gpio1. */
521 	write_cfg_reg_1(sc, NCT_LD7_GPIO_ENABLE,
522 		read_cfg_reg_1(sc, NCT_LD7_GPIO_ENABLE) | 0x03);
523 
524 	for (i = 0; i <= NCT_MAX_PIN; i++) {
525 		struct gpio_pin *pin;
526 
527 		pin = &sc->pins[i];
528 		pin->gp_pin = i;
529 		pin->gp_caps = NCT_GPIO_CAPS;
530 		pin->gp_flags = 0;
531 
532 		snprintf(pin->gp_name, GPIOMAXNAME, "GPIO%02u", i);
533 		pin->gp_name[GPIOMAXNAME - 1] = '\0';
534 
535 		if (nct_pin_is_input(sc, i))
536 			pin->gp_flags |= GPIO_PIN_INPUT;
537 		else
538 			pin->gp_flags |= GPIO_PIN_OUTPUT;
539 
540 		if (nct_pin_is_opendrain(sc, i))
541 			pin->gp_flags |= GPIO_PIN_OPENDRAIN;
542 		else
543 			pin->gp_flags |= GPIO_PIN_PUSHPULL;
544 
545 		if (nct_pin_is_inverted(sc, i))
546 			pin->gp_flags |= (GPIO_PIN_INVIN | GPIO_PIN_INVOUT);
547 	}
548 	GPIO_UNLOCK(sc);
549 
550 	sc->busdev = gpiobus_attach_bus(dev);
551 	if (sc->busdev == NULL) {
552 		GPIO_ASSERT_UNLOCKED(sc);
553 		GPIO_LOCK(sc);
554 		ext_cfg_exit(sc);
555 		GPIO_UNLOCK(sc);
556 		bus_release_resource(dev, SYS_RES_IOPORT, sc->rid, sc->portres);
557 		GPIO_LOCK_DESTROY(sc);
558 
559 		return (ENXIO);
560 	}
561 
562 	return (0);
563 }
564 
565 static int
566 nct_detach(device_t dev)
567 {
568 	struct nct_softc *sc;
569 
570 	sc = device_get_softc(dev);
571 	gpiobus_detach_bus(dev);
572 
573 	GPIO_ASSERT_UNLOCKED(sc);
574 	GPIO_LOCK(sc);
575 	ext_cfg_exit(sc);
576 	GPIO_UNLOCK(sc);
577 
578 	/* Cleanup resources. */
579 	bus_release_resource(dev, SYS_RES_IOPORT, sc->rid, sc->portres);
580 
581 	GPIO_LOCK_DESTROY(sc);
582 
583 	return (0);
584 }
585 
586 static device_t
587 nct_gpio_get_bus(device_t dev)
588 {
589 	struct nct_softc *sc;
590 
591 	sc = device_get_softc(dev);
592 
593 	return (sc->busdev);
594 }
595 
596 static int
597 nct_gpio_pin_max(device_t dev, int *npins)
598 {
599 	*npins = NCT_MAX_PIN;
600 
601 	return (0);
602 }
603 
604 static int
605 nct_gpio_pin_set(device_t dev, uint32_t pin_num, uint32_t pin_value)
606 {
607 	struct nct_softc *sc;
608 
609 	if (!NCT_IS_VALID_PIN(pin_num))
610 		return (EINVAL);
611 
612 	sc = device_get_softc(dev);
613 	GPIO_ASSERT_UNLOCKED(sc);
614 	GPIO_LOCK(sc);
615 	nct_write_pin(sc, pin_num, pin_value);
616 	GPIO_UNLOCK(sc);
617 
618 	return (0);
619 }
620 
621 static int
622 nct_gpio_pin_get(device_t dev, uint32_t pin_num, uint32_t *pin_value)
623 {
624 	struct nct_softc *sc;
625 
626 	if (!NCT_IS_VALID_PIN(pin_num))
627 		return (EINVAL);
628 
629 	sc = device_get_softc(dev);
630 	GPIO_ASSERT_UNLOCKED(sc);
631 	GPIO_LOCK(sc);
632 	*pin_value = nct_read_pin(sc, pin_num);
633 	GPIO_UNLOCK(sc);
634 
635 	return (0);
636 }
637 
638 static int
639 nct_gpio_pin_toggle(device_t dev, uint32_t pin_num)
640 {
641 	struct nct_softc *sc;
642 
643 	if (!NCT_IS_VALID_PIN(pin_num))
644 		return (EINVAL);
645 
646 	sc = device_get_softc(dev);
647 	GPIO_ASSERT_UNLOCKED(sc);
648 	GPIO_LOCK(sc);
649 	if (nct_read_pin(sc, pin_num))
650 		nct_write_pin(sc, pin_num, 0);
651 	else
652 		nct_write_pin(sc, pin_num, 1);
653 
654 	GPIO_UNLOCK(sc);
655 
656 	return (0);
657 }
658 
659 static int
660 nct_gpio_pin_getcaps(device_t dev, uint32_t pin_num, uint32_t *caps)
661 {
662 	struct nct_softc *sc;
663 
664 	if (!NCT_IS_VALID_PIN(pin_num))
665 		return (EINVAL);
666 
667 	sc = device_get_softc(dev);
668 	GPIO_ASSERT_UNLOCKED(sc);
669 	GPIO_LOCK(sc);
670 	*caps = sc->pins[pin_num].gp_caps;
671 	GPIO_UNLOCK(sc);
672 
673 	return (0);
674 }
675 
676 static int
677 nct_gpio_pin_getflags(device_t dev, uint32_t pin_num, uint32_t *flags)
678 {
679 	struct nct_softc *sc;
680 
681 	if (!NCT_IS_VALID_PIN(pin_num))
682 		return (EINVAL);
683 
684 	sc = device_get_softc(dev);
685 	GPIO_ASSERT_UNLOCKED(sc);
686 	GPIO_LOCK(sc);
687 	*flags = sc->pins[pin_num].gp_flags;
688 	GPIO_UNLOCK(sc);
689 
690 	return (0);
691 }
692 
693 static int
694 nct_gpio_pin_getname(device_t dev, uint32_t pin_num, char *name)
695 {
696 	struct nct_softc *sc;
697 
698 	if (!NCT_IS_VALID_PIN(pin_num))
699 		return (EINVAL);
700 
701 	sc = device_get_softc(dev);
702 	GPIO_ASSERT_UNLOCKED(sc);
703 	GPIO_LOCK(sc);
704 	memcpy(name, sc->pins[pin_num].gp_name, GPIOMAXNAME);
705 	GPIO_UNLOCK(sc);
706 
707 	return (0);
708 }
709 
710 static int
711 nct_gpio_pin_setflags(device_t dev, uint32_t pin_num, uint32_t flags)
712 {
713 	struct nct_softc *sc;
714 	struct gpio_pin *pin;
715 
716 	if (!NCT_IS_VALID_PIN(pin_num))
717 		return (EINVAL);
718 
719 	sc = device_get_softc(dev);
720 	pin = &sc->pins[pin_num];
721 	if ((flags & pin->gp_caps) != flags)
722 		return (EINVAL);
723 
724 	GPIO_ASSERT_UNLOCKED(sc);
725 	GPIO_LOCK(sc);
726 	if (flags & (GPIO_PIN_INPUT | GPIO_PIN_OUTPUT)) {
727 		if ((flags & (GPIO_PIN_INPUT | GPIO_PIN_OUTPUT)) ==
728 			(GPIO_PIN_INPUT | GPIO_PIN_OUTPUT)) {
729 				GPIO_UNLOCK(sc);
730 				return (EINVAL);
731 		}
732 
733 		if (flags & GPIO_PIN_INPUT)
734 			nct_set_pin_is_input(sc, pin_num);
735 		else
736 			nct_set_pin_is_output(sc, pin_num);
737 	}
738 
739 	if (flags & (GPIO_PIN_OPENDRAIN | GPIO_PIN_PUSHPULL)) {
740 		if (flags & GPIO_PIN_INPUT) {
741 			GPIO_UNLOCK(sc);
742 			return (EINVAL);
743 		}
744 
745 		if ((flags & (GPIO_PIN_OPENDRAIN | GPIO_PIN_PUSHPULL)) ==
746 			(GPIO_PIN_OPENDRAIN | GPIO_PIN_PUSHPULL)) {
747 				GPIO_UNLOCK(sc);
748 				return (EINVAL);
749 		}
750 
751 		if (flags & GPIO_PIN_OPENDRAIN)
752 			nct_set_pin_opendrain(sc, pin_num);
753 		else
754 			nct_set_pin_pushpull(sc, pin_num);
755 	}
756 
757 	if (flags & (GPIO_PIN_INVIN | GPIO_PIN_INVOUT)) {
758 		if ((flags & (GPIO_PIN_INVIN | GPIO_PIN_INVOUT)) !=
759 			(GPIO_PIN_INVIN | GPIO_PIN_INVOUT)) {
760 				GPIO_UNLOCK(sc);
761 				return (EINVAL);
762 		}
763 
764 		if (flags & GPIO_PIN_INVIN)
765 			nct_set_pin_is_inverted(sc, pin_num);
766 		else
767 			nct_set_pin_not_inverted(sc, pin_num);
768 	}
769 
770 	pin->gp_flags = flags;
771 	GPIO_UNLOCK(sc);
772 
773 	return (0);
774 }
775 
776 static device_method_t nct_methods[] = {
777 	/* Device interface */
778 	DEVMETHOD(device_identify,	nct_identify),
779 	DEVMETHOD(device_probe,		nct_probe),
780 	DEVMETHOD(device_attach,	nct_attach),
781 	DEVMETHOD(device_detach,	nct_detach),
782 
783 	/* GPIO */
784 	DEVMETHOD(gpio_get_bus,			nct_gpio_get_bus),
785 	DEVMETHOD(gpio_pin_max,			nct_gpio_pin_max),
786 	DEVMETHOD(gpio_pin_get,			nct_gpio_pin_get),
787 	DEVMETHOD(gpio_pin_set,			nct_gpio_pin_set),
788 	DEVMETHOD(gpio_pin_toggle,		nct_gpio_pin_toggle),
789 	DEVMETHOD(gpio_pin_getname,		nct_gpio_pin_getname),
790 	DEVMETHOD(gpio_pin_getcaps,		nct_gpio_pin_getcaps),
791 	DEVMETHOD(gpio_pin_getflags,	nct_gpio_pin_getflags),
792 	DEVMETHOD(gpio_pin_setflags,	nct_gpio_pin_setflags),
793 
794 	DEVMETHOD_END
795 };
796 
797 static driver_t nct_isa_driver = {
798 	"gpio",
799 	nct_methods,
800 	sizeof(struct nct_softc)
801 };
802 
803 static devclass_t nct_devclass;
804 
805 DRIVER_MODULE(nctgpio, isa, nct_isa_driver, nct_devclass, NULL, NULL);
806 MODULE_DEPEND(nctgpio, gpiobus, 1, 1, 1);
807