xref: /freebsd/sys/dev/nctgpio/nctgpio.c (revision 273c26a3c3bea87a241d6879abd4f991db180bf0)
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);
803