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: releng/11.0/sys/dev/nctgpio/nctgpio.c 298322 2016-04-20 01:17:18Z cem $
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
98struct 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
122static void	ext_cfg_enter(struct nct_softc *);
123static void	ext_cfg_exit(struct nct_softc *);
124
125/*
126 * Potential Extended Function Enable Register addresses.
127 * Same address as EFIR.
128 */
129uint8_t probe_addrs[] = {0x2e, 0x4e};
130
131struct 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
145static void
146write_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
155static uint8_t
156read_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
169static uint16_t
170read_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 */
184static void
185ext_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 */
198static void
199ext_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 */
209static void
210select_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 */
219static uint8_t
220nct_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 */
234static uint8_t
235nct_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 */
250static uint8_t
251nct_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 */
266static uint8_t
267nct_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 */
281static void
282nct_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 */
297static void
298nct_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 */
313static bool
314nct_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 */
329static void
330nct_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
346static bool
347nct_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
357static void
358nct_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
370static void
371nct_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
383static bool
384nct_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
396static void
397nct_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
409static void
410nct_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
422static bool
423nct_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
435static void
436nct_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
444static int
445nct_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
494static int
495nct_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
561static int
562nct_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
582static device_t
583nct_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
592static int
593nct_gpio_pin_max(device_t dev, int *npins)
594{
595	*npins = NCT_MAX_PIN;
596
597	return (0);
598}
599
600static int
601nct_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
617static int
618nct_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
634static int
635nct_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
655static int
656nct_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
672static int
673nct_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
689static int
690nct_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
706static int
707nct_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
772static 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
793static driver_t nct_isa_driver = {
794	"gpio",
795	nct_methods,
796	sizeof(struct nct_softc)
797};
798
799static devclass_t nct_devclass;
800
801DRIVER_MODULE(nctgpio, isa, nct_isa_driver, nct_devclass, NULL, NULL);
802MODULE_DEPEND(nctgpio, gpiobus, 1, 1, 1);
803