1 /*-
2 * Copyright (c) 2016 Daniel Wyatt <[email protected]>
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
write_cfg_reg_1(struct nct_softc * sc,uint8_t reg,uint8_t value)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
read_cfg_reg_1(struct nct_softc * sc,uint8_t reg)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
read_cfg_reg_2(struct nct_softc * sc,uint8_t reg)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
ext_cfg_enter(struct nct_softc * sc)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
ext_cfg_exit(struct nct_softc * sc)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
select_ldn(struct nct_softc * sc,uint8_t ldn)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
nct_ior_addr(uint32_t pin_num)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
nct_dat_addr(uint32_t pin_num)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
nct_inv_addr(uint32_t pin_num)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
nct_outcfg_addr(uint32_t pin_num)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
nct_set_pin_is_output(struct nct_softc * sc,uint32_t pin_num)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
nct_set_pin_is_input(struct nct_softc * sc,uint32_t pin_num)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
nct_pin_is_input(struct nct_softc * sc,uint32_t pin_num)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
nct_write_pin(struct nct_softc * sc,uint32_t pin_num,uint8_t data)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
nct_read_pin(struct nct_softc * sc,uint32_t pin_num)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
nct_set_pin_is_inverted(struct nct_softc * sc,uint32_t pin_num)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
nct_set_pin_not_inverted(struct nct_softc * sc,uint32_t pin_num)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
nct_pin_is_inverted(struct nct_softc * sc,uint32_t pin_num)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
nct_set_pin_opendrain(struct nct_softc * sc,uint32_t pin_num)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
nct_set_pin_pushpull(struct nct_softc * sc,uint32_t pin_num)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
nct_pin_is_opendrain(struct nct_softc * sc,uint32_t pin_num)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
nct_identify(driver_t * driver,device_t parent)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
nct_probe(device_t dev)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
nct_attach(device_t dev)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%02o", 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
nct_detach(device_t dev)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
nct_gpio_get_bus(device_t dev)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
nct_gpio_pin_max(device_t dev,int * npins)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
nct_gpio_pin_set(device_t dev,uint32_t pin_num,uint32_t pin_value)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
nct_gpio_pin_get(device_t dev,uint32_t pin_num,uint32_t * pin_value)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
nct_gpio_pin_toggle(device_t dev,uint32_t pin_num)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
nct_gpio_pin_getcaps(device_t dev,uint32_t pin_num,uint32_t * caps)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
nct_gpio_pin_getflags(device_t dev,uint32_t pin_num,uint32_t * flags)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
nct_gpio_pin_getname(device_t dev,uint32_t pin_num,char * name)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
nct_gpio_pin_setflags(device_t dev,uint32_t pin_num,uint32_t flags)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