16b7b2d80SAdrian Chadd /*- 26b7b2d80SAdrian Chadd * Copyright (c) 2016 Daniel Wyatt <Daniel.Wyatt@gmail.com> 36b7b2d80SAdrian Chadd * All rights reserved. 46b7b2d80SAdrian Chadd * 56b7b2d80SAdrian Chadd * Redistribution and use in source and binary forms, with or without 66b7b2d80SAdrian Chadd * modification, are permitted provided that the following conditions 76b7b2d80SAdrian Chadd * are met: 86b7b2d80SAdrian Chadd * 1. Redistributions of source code must retain the above copyright 96b7b2d80SAdrian Chadd * notice, this list of conditions and the following disclaimer. 106b7b2d80SAdrian Chadd * 2. Redistributions in binary form must reproduce the above copyright 116b7b2d80SAdrian Chadd * notice, this list of conditions and the following disclaimer in the 126b7b2d80SAdrian Chadd * documentation and/or other materials provided with the distribution. 136b7b2d80SAdrian Chadd * 146b7b2d80SAdrian Chadd * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND 156b7b2d80SAdrian Chadd * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 166b7b2d80SAdrian Chadd * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 176b7b2d80SAdrian Chadd * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE 186b7b2d80SAdrian Chadd * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 196b7b2d80SAdrian Chadd * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 206b7b2d80SAdrian Chadd * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 216b7b2d80SAdrian Chadd * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 226b7b2d80SAdrian Chadd * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 236b7b2d80SAdrian Chadd * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 246b7b2d80SAdrian Chadd * SUCH DAMAGE. 256b7b2d80SAdrian Chadd * 266b7b2d80SAdrian Chadd * $FreeBSD$ 276b7b2d80SAdrian Chadd * 286b7b2d80SAdrian Chadd */ 296b7b2d80SAdrian Chadd 306b7b2d80SAdrian Chadd /* 316b7b2d80SAdrian Chadd * Nuvoton GPIO driver. 326b7b2d80SAdrian Chadd */ 336b7b2d80SAdrian Chadd 346b7b2d80SAdrian Chadd #include <sys/cdefs.h> 356b7b2d80SAdrian Chadd 366b7b2d80SAdrian Chadd #include <sys/param.h> 376b7b2d80SAdrian Chadd #include <sys/kernel.h> 386b7b2d80SAdrian Chadd #include <sys/systm.h> 396b7b2d80SAdrian Chadd #include <sys/bus.h> 406b7b2d80SAdrian Chadd #include <sys/eventhandler.h> 416b7b2d80SAdrian Chadd #include <sys/lock.h> 426b7b2d80SAdrian Chadd 436b7b2d80SAdrian Chadd #include <sys/module.h> 446b7b2d80SAdrian Chadd #include <sys/gpio.h> 456b7b2d80SAdrian Chadd 466b7b2d80SAdrian Chadd #include <machine/bus.h> 476b7b2d80SAdrian Chadd 486b7b2d80SAdrian Chadd #include <dev/gpio/gpiobusvar.h> 49e3df342aSAndriy Gapon #include <dev/superio/superio.h> 506b7b2d80SAdrian Chadd 516b7b2d80SAdrian Chadd #include "gpio_if.h" 526b7b2d80SAdrian Chadd 537f8d2ed0SStéphane Rochoy #define NCT_PPOD_LDN 0xf /* LDN used to select Push-Pull/Open-Drain */ 546b7b2d80SAdrian Chadd 557f8d2ed0SStéphane Rochoy /* Direct access through GPIO register table */ 567f8d2ed0SStéphane Rochoy #define NCT_IO_GSR 0 /* Group Select */ 577f8d2ed0SStéphane Rochoy #define NCT_IO_IOR 1 /* I/O */ 587f8d2ed0SStéphane Rochoy #define NCT_IO_DAT 2 /* Data */ 597f8d2ed0SStéphane Rochoy #define NCT_IO_INV 3 /* Inversion */ 607f8d2ed0SStéphane Rochoy #define NCT_IO_DST 4 /* Status */ 616b7b2d80SAdrian Chadd 627f8d2ed0SStéphane Rochoy #define NCT_MAX_GROUP 9 637f8d2ed0SStéphane Rochoy #define NCT_MAX_PIN 75 646b7b2d80SAdrian Chadd 657f8d2ed0SStéphane Rochoy #define NCT_PIN_IS_VALID(_sc, _p) ((_p) < (_sc)->npins) 667f8d2ed0SStéphane Rochoy #define NCT_PIN_GROUP(_sc, _p) ((_sc)->pinmap[(_p)].group) 677f8d2ed0SStéphane Rochoy #define NCT_PIN_GRPNUM(_sc, _p) ((_sc)->pinmap[(_p)].grpnum) 687f8d2ed0SStéphane Rochoy #define NCT_PIN_BIT(_sc, _p) ((_sc)->pinmap[(_p)].bit) 697f8d2ed0SStéphane Rochoy #define NCT_PIN_BITMASK(_p) (1 << ((_p) & 7)) 706b7b2d80SAdrian Chadd 716b7b2d80SAdrian Chadd #define NCT_GPIO_CAPS (GPIO_PIN_INPUT | GPIO_PIN_OUTPUT | \ 726b7b2d80SAdrian Chadd GPIO_PIN_OPENDRAIN | GPIO_PIN_PUSHPULL | \ 736b7b2d80SAdrian Chadd GPIO_PIN_INVIN | GPIO_PIN_INVOUT) 746b7b2d80SAdrian Chadd 757f8d2ed0SStéphane Rochoy #define NCT_PREFER_INDIRECT_CHANNEL 2 767f8d2ed0SStéphane Rochoy 777f8d2ed0SStéphane Rochoy #define NCT_VERBOSE_PRINTF(dev, ...) \ 787f8d2ed0SStéphane Rochoy do { \ 797f8d2ed0SStéphane Rochoy if (__predict_false(bootverbose)) \ 807f8d2ed0SStéphane Rochoy device_printf(dev, __VA_ARGS__); \ 817f8d2ed0SStéphane Rochoy } while (0) 827f8d2ed0SStéphane Rochoy 83155514eaSAndriy Gapon /* 84155514eaSAndriy Gapon * Note that the values are important. 85155514eaSAndriy Gapon * They match actual register offsets. 86155514eaSAndriy Gapon */ 87155514eaSAndriy Gapon typedef enum { 88155514eaSAndriy Gapon REG_IOR = 0, 89155514eaSAndriy Gapon REG_DAT = 1, 90155514eaSAndriy Gapon REG_INV = 2, 91155514eaSAndriy Gapon } reg_t; 92155514eaSAndriy Gapon 937f8d2ed0SStéphane Rochoy struct nct_gpio_group { 947f8d2ed0SStéphane Rochoy uint32_t caps; 957f8d2ed0SStéphane Rochoy uint8_t enable_ldn; 967f8d2ed0SStéphane Rochoy uint8_t enable_reg; 977f8d2ed0SStéphane Rochoy uint8_t enable_mask; 987f8d2ed0SStéphane Rochoy uint8_t data_ldn; 997f8d2ed0SStéphane Rochoy uint8_t iobase; 1007f8d2ed0SStéphane Rochoy uint8_t ppod_reg; /* Push-Pull/Open-Drain */ 1017f8d2ed0SStéphane Rochoy uint8_t grpnum; 1027f8d2ed0SStéphane Rochoy uint8_t pinbits[8]; 1037f8d2ed0SStéphane Rochoy uint8_t npins; 1047f8d2ed0SStéphane Rochoy }; 1057f8d2ed0SStéphane Rochoy 1066b7b2d80SAdrian Chadd struct nct_softc { 1076b7b2d80SAdrian Chadd device_t dev; 1086b7b2d80SAdrian Chadd device_t busdev; 1096b7b2d80SAdrian Chadd struct mtx mtx; 110155514eaSAndriy Gapon struct resource *iores; 111155514eaSAndriy Gapon int iorid; 112155514eaSAndriy Gapon int curgrp; 113155514eaSAndriy Gapon struct { 1147f8d2ed0SStéphane Rochoy uint8_t ior[NCT_MAX_GROUP + 1]; /* direction, 1: input 0: output */ 1157f8d2ed0SStéphane Rochoy uint8_t out[NCT_MAX_GROUP + 1]; /* output value */ 1167f8d2ed0SStéphane Rochoy uint8_t out_known[NCT_MAX_GROUP + 1]; /* whether out is valid */ 1177f8d2ed0SStéphane Rochoy uint8_t inv[NCT_MAX_GROUP + 1]; /* inversion, 1: inverted */ 118155514eaSAndriy Gapon } cache; 119523af57eSConrad Meyer struct gpio_pin pins[NCT_MAX_PIN + 1]; 1207f8d2ed0SStéphane Rochoy struct nct_device *nctdevp; 1217f8d2ed0SStéphane Rochoy int npins; /* Total number of pins */ 1227f8d2ed0SStéphane Rochoy 1237f8d2ed0SStéphane Rochoy /* Lookup tables */ 1247f8d2ed0SStéphane Rochoy struct { 1257f8d2ed0SStéphane Rochoy struct nct_gpio_group *group; 1267f8d2ed0SStéphane Rochoy uint8_t grpnum; 1277f8d2ed0SStéphane Rochoy uint8_t bit; 1287f8d2ed0SStéphane Rochoy } pinmap[NCT_MAX_PIN+1]; 1297f8d2ed0SStéphane Rochoy struct nct_gpio_group *grpmap[NCT_MAX_GROUP+1]; 1306b7b2d80SAdrian Chadd }; 1316b7b2d80SAdrian Chadd 1326b7b2d80SAdrian Chadd #define GPIO_LOCK_INIT(_sc) mtx_init(&(_sc)->mtx, \ 1336b7b2d80SAdrian Chadd device_get_nameunit(dev), NULL, MTX_DEF) 1346b7b2d80SAdrian Chadd #define GPIO_LOCK_DESTROY(_sc) mtx_destroy(&(_sc)->mtx) 1356b7b2d80SAdrian Chadd #define GPIO_LOCK(_sc) mtx_lock(&(_sc)->mtx) 1366b7b2d80SAdrian Chadd #define GPIO_UNLOCK(_sc) mtx_unlock(&(_sc)->mtx) 1376b7b2d80SAdrian Chadd #define GPIO_ASSERT_LOCKED(_sc) mtx_assert(&(_sc)->mtx, MA_OWNED) 1386b7b2d80SAdrian Chadd #define GPIO_ASSERT_UNLOCKED(_sc) mtx_assert(&(_sc)->mtx, MA_NOTOWNED) 1396b7b2d80SAdrian Chadd 1407f8d2ed0SStéphane Rochoy #define GET_BIT(v, b) (((v) >> (b)) & 1) 1417f8d2ed0SStéphane Rochoy 1427f8d2ed0SStéphane Rochoy /* 1437f8d2ed0SStéphane Rochoy * For most devices there are several GPIO devices, we attach only to one of 1447f8d2ed0SStéphane Rochoy * them and use the rest without attaching. 1457f8d2ed0SStéphane Rochoy */ 1467f8d2ed0SStéphane Rochoy struct nct_device { 1477f8d2ed0SStéphane Rochoy uint16_t devid; 1487f8d2ed0SStéphane Rochoy int extid; 1496b7b2d80SAdrian Chadd const char *descr; 1507f8d2ed0SStéphane Rochoy int ngroups; 1517f8d2ed0SStéphane Rochoy struct nct_gpio_group groups[NCT_MAX_GROUP + 1]; 1527f8d2ed0SStéphane Rochoy } nct_devices[] = { 1536b7b2d80SAdrian Chadd { 1548e6ea10cSStéphane Rochoy .devid = 0xa025, 1558e6ea10cSStéphane Rochoy .descr = "GPIO on Winbond 83627DHG IC ver. 5", 1568e6ea10cSStéphane Rochoy .ngroups = 5, 1578e6ea10cSStéphane Rochoy .groups = { 1588e6ea10cSStéphane Rochoy { 1598e6ea10cSStéphane Rochoy .grpnum = 2, 1608e6ea10cSStéphane Rochoy .pinbits = { 0, 1, 2, 3, 4, 5, 6, 7 }, 1618e6ea10cSStéphane Rochoy .enable_ldn = 0x09, 1628e6ea10cSStéphane Rochoy .enable_reg = 0x30, 1638e6ea10cSStéphane Rochoy .enable_mask = 0x01, 1648e6ea10cSStéphane Rochoy .data_ldn = 0x09, 1658e6ea10cSStéphane Rochoy .ppod_reg = 0xe0, /* FIXME Need to check for this group. */ 1668e6ea10cSStéphane Rochoy .caps = NCT_GPIO_CAPS, 1678e6ea10cSStéphane Rochoy .npins = 8, 1688e6ea10cSStéphane Rochoy .iobase = 0xe3, 1698e6ea10cSStéphane Rochoy }, 1708e6ea10cSStéphane Rochoy { 1718e6ea10cSStéphane Rochoy .grpnum = 3, 1728e6ea10cSStéphane Rochoy .pinbits = { 0, 1, 2, 3, 4, 5, 6, 7 }, 1738e6ea10cSStéphane Rochoy .enable_ldn = 0x09, 1748e6ea10cSStéphane Rochoy .enable_reg = 0x30, 1758e6ea10cSStéphane Rochoy .enable_mask = 0x02, 1768e6ea10cSStéphane Rochoy .data_ldn = 0x09, 1778e6ea10cSStéphane Rochoy .ppod_reg = 0xe1, /* FIXME Need to check for this group. */ 1788e6ea10cSStéphane Rochoy .caps = NCT_GPIO_CAPS, 1798e6ea10cSStéphane Rochoy .npins = 8, 1808e6ea10cSStéphane Rochoy .iobase = 0xf0, 1818e6ea10cSStéphane Rochoy }, 1828e6ea10cSStéphane Rochoy { 1838e6ea10cSStéphane Rochoy .grpnum = 4, 1848e6ea10cSStéphane Rochoy .pinbits = { 0, 1, 2, 3, 4, 5, 6, 7 }, 1858e6ea10cSStéphane Rochoy .enable_ldn = 0x09, 1868e6ea10cSStéphane Rochoy .enable_reg = 0x30, 1878e6ea10cSStéphane Rochoy .enable_mask = 0x04, 1888e6ea10cSStéphane Rochoy .data_ldn = 0x09, 1898e6ea10cSStéphane Rochoy .ppod_reg = 0xe1, /* FIXME Need to check for this group. */ 1908e6ea10cSStéphane Rochoy .caps = NCT_GPIO_CAPS, 1918e6ea10cSStéphane Rochoy .npins = 8, 1928e6ea10cSStéphane Rochoy .iobase = 0xf4, 1938e6ea10cSStéphane Rochoy }, 1948e6ea10cSStéphane Rochoy { 1958e6ea10cSStéphane Rochoy .grpnum = 5, 1968e6ea10cSStéphane Rochoy .pinbits = { 0, 1, 2, 3, 4, 5, 6, 7 }, 1978e6ea10cSStéphane Rochoy .enable_ldn = 0x09, 1988e6ea10cSStéphane Rochoy .enable_reg = 0x30, 1998e6ea10cSStéphane Rochoy .enable_mask = 0x08, 2008e6ea10cSStéphane Rochoy .data_ldn = 0x09, 2018e6ea10cSStéphane Rochoy .ppod_reg = 0xe1, /* FIXME Need to check for this group. */ 2028e6ea10cSStéphane Rochoy .caps = NCT_GPIO_CAPS, 2038e6ea10cSStéphane Rochoy .npins = 8, 2048e6ea10cSStéphane Rochoy .iobase = 0xe0, 2058e6ea10cSStéphane Rochoy }, 2068e6ea10cSStéphane Rochoy { 2078e6ea10cSStéphane Rochoy .grpnum = 6, 2088e6ea10cSStéphane Rochoy .pinbits = { 0, 1, 2, 3, 4, 5, 6, 7 }, 2098e6ea10cSStéphane Rochoy .enable_ldn = 0x07, 2108e6ea10cSStéphane Rochoy .enable_reg = 0x30, 2118e6ea10cSStéphane Rochoy .enable_mask = 0x01, 2128e6ea10cSStéphane Rochoy .data_ldn = 0x07, 2138e6ea10cSStéphane Rochoy .ppod_reg = 0xe1, /* FIXME Need to check for this group. */ 2148e6ea10cSStéphane Rochoy .caps = NCT_GPIO_CAPS, 2158e6ea10cSStéphane Rochoy .npins = 8, 2168e6ea10cSStéphane Rochoy .iobase = 0xf4, 2178e6ea10cSStéphane Rochoy }, 2188e6ea10cSStéphane Rochoy }, 2198e6ea10cSStéphane Rochoy }, 2208e6ea10cSStéphane Rochoy { 2217f8d2ed0SStéphane Rochoy .devid = 0x1061, 2227f8d2ed0SStéphane Rochoy .descr = "GPIO on Nuvoton NCT5104D", 2237f8d2ed0SStéphane Rochoy .ngroups = 2, 2247f8d2ed0SStéphane Rochoy .groups = { 2257f8d2ed0SStéphane Rochoy { 2267f8d2ed0SStéphane Rochoy .grpnum = 0, 2277f8d2ed0SStéphane Rochoy .pinbits = { 0, 1, 2, 3, 4, 5, 6, 7 }, 2287f8d2ed0SStéphane Rochoy .enable_ldn = 0x07, 2297f8d2ed0SStéphane Rochoy .enable_reg = 0x30, 2307f8d2ed0SStéphane Rochoy .enable_mask = 0x01, 2317f8d2ed0SStéphane Rochoy .data_ldn = 0x07, 2327f8d2ed0SStéphane Rochoy .ppod_reg = 0xe0, 2337f8d2ed0SStéphane Rochoy .caps = NCT_GPIO_CAPS, 2347f8d2ed0SStéphane Rochoy .npins = 8, 2357f8d2ed0SStéphane Rochoy .iobase = 0xe0, 2366b7b2d80SAdrian Chadd }, 2376b7b2d80SAdrian Chadd { 2387f8d2ed0SStéphane Rochoy .grpnum = 1, 2397f8d2ed0SStéphane Rochoy .pinbits = { 0, 1, 2, 3, 4, 5, 6, 7 }, 2407f8d2ed0SStéphane Rochoy .enable_ldn = 0x07, 2417f8d2ed0SStéphane Rochoy .enable_reg = 0x30, 2427f8d2ed0SStéphane Rochoy .enable_mask = 0x02, 2437f8d2ed0SStéphane Rochoy .data_ldn = 0x07, 2447f8d2ed0SStéphane Rochoy .ppod_reg = 0xe1, 2457f8d2ed0SStéphane Rochoy .caps = NCT_GPIO_CAPS, 2467f8d2ed0SStéphane Rochoy .npins = 8, 2477f8d2ed0SStéphane Rochoy .iobase = 0xe4, 2487f8d2ed0SStéphane Rochoy }, 2497f8d2ed0SStéphane Rochoy }, 2506b7b2d80SAdrian Chadd }, 2519d1208bbSOleksandr Tymoshenko { 2528e6ea10cSStéphane Rochoy .devid = 0xc452, /* FIXME Conflict with Nuvoton NCT6106D. See NetBSD's nct_match. */ 2537f8d2ed0SStéphane Rochoy .descr = "GPIO on Nuvoton NCT5104D (PC-Engines APU)", 2547f8d2ed0SStéphane Rochoy .ngroups = 2, 2557f8d2ed0SStéphane Rochoy .groups = { 2567f8d2ed0SStéphane Rochoy { 2577f8d2ed0SStéphane Rochoy .grpnum = 0, 2587f8d2ed0SStéphane Rochoy .pinbits = { 0, 1, 2, 3, 4, 5, 6, 7 }, 2597f8d2ed0SStéphane Rochoy .enable_ldn = 0x07, 2607f8d2ed0SStéphane Rochoy .enable_reg = 0x30, 2617f8d2ed0SStéphane Rochoy .enable_mask = 0x01, 2627f8d2ed0SStéphane Rochoy .data_ldn = 0x07, 2637f8d2ed0SStéphane Rochoy .ppod_reg = 0xe0, 2647f8d2ed0SStéphane Rochoy .caps = NCT_GPIO_CAPS, 2657f8d2ed0SStéphane Rochoy .npins = 8, 2667f8d2ed0SStéphane Rochoy .iobase = 0xe0, 2677f8d2ed0SStéphane Rochoy }, 2687f8d2ed0SStéphane Rochoy { 2697f8d2ed0SStéphane Rochoy .grpnum = 1, 2707f8d2ed0SStéphane Rochoy .pinbits = { 0, 1, 2, 3, 4, 5, 6, 7 }, 2717f8d2ed0SStéphane Rochoy .enable_ldn = 0x07, 2727f8d2ed0SStéphane Rochoy .enable_reg = 0x30, 2737f8d2ed0SStéphane Rochoy .enable_mask = 0x02, 2747f8d2ed0SStéphane Rochoy .data_ldn = 0x07, 2757f8d2ed0SStéphane Rochoy .ppod_reg = 0xe1, 2767f8d2ed0SStéphane Rochoy .caps = NCT_GPIO_CAPS, 2777f8d2ed0SStéphane Rochoy .npins = 8, 2787f8d2ed0SStéphane Rochoy .iobase = 0xe4, 2797f8d2ed0SStéphane Rochoy }, 2807f8d2ed0SStéphane Rochoy }, 2817f8d2ed0SStéphane Rochoy }, 2827f8d2ed0SStéphane Rochoy { 2837f8d2ed0SStéphane Rochoy .devid = 0xc453, 2847f8d2ed0SStéphane Rochoy .descr = "GPIO on Nuvoton NCT5104D (PC-Engines APU3)", 2857f8d2ed0SStéphane Rochoy .ngroups = 2, 2867f8d2ed0SStéphane Rochoy .groups = { 2877f8d2ed0SStéphane Rochoy { 2887f8d2ed0SStéphane Rochoy .grpnum = 0, 2897f8d2ed0SStéphane Rochoy .pinbits = { 0, 1, 2, 3, 4, 5, 6, 7 }, 2907f8d2ed0SStéphane Rochoy .enable_ldn = 0x07, 2917f8d2ed0SStéphane Rochoy .enable_reg = 0x30, 2927f8d2ed0SStéphane Rochoy .enable_mask = 0x01, 2937f8d2ed0SStéphane Rochoy .data_ldn = 0x07, 2947f8d2ed0SStéphane Rochoy .ppod_reg = 0xe0, 2957f8d2ed0SStéphane Rochoy .caps = NCT_GPIO_CAPS, 2967f8d2ed0SStéphane Rochoy .npins = 8, 2977f8d2ed0SStéphane Rochoy .iobase = 0xe0, 2987f8d2ed0SStéphane Rochoy }, 2997f8d2ed0SStéphane Rochoy { 3007f8d2ed0SStéphane Rochoy .grpnum = 1, 3017f8d2ed0SStéphane Rochoy .pinbits = { 0, 1, 2, 3, 4, 5, 6, 7 }, 3027f8d2ed0SStéphane Rochoy .enable_ldn = 0x07, 3037f8d2ed0SStéphane Rochoy .enable_reg = 0x30, 3047f8d2ed0SStéphane Rochoy .enable_mask = 0x02, 3057f8d2ed0SStéphane Rochoy .data_ldn = 0x07, 3067f8d2ed0SStéphane Rochoy .ppod_reg = 0xe1, 3077f8d2ed0SStéphane Rochoy .caps = NCT_GPIO_CAPS, 3087f8d2ed0SStéphane Rochoy .npins = 8, 3097f8d2ed0SStéphane Rochoy .iobase = 0xe4, 3107f8d2ed0SStéphane Rochoy }, 3117f8d2ed0SStéphane Rochoy }, 3129d1208bbSOleksandr Tymoshenko }, 3138e6ea10cSStéphane Rochoy { 3148e6ea10cSStéphane Rochoy .devid = 0xd42a, 3158e6ea10cSStéphane Rochoy .extid = 1, 3168e6ea10cSStéphane Rochoy .descr = "GPIO on Nuvoton NCT6796D-E", 3178e6ea10cSStéphane Rochoy .ngroups = 10, 3188e6ea10cSStéphane Rochoy .groups = { 3198e6ea10cSStéphane Rochoy { 3208e6ea10cSStéphane Rochoy .grpnum = 0, 3218e6ea10cSStéphane Rochoy .pinbits = { 0, 1, 2, 3, 4, 5, 6, 7 }, 3228e6ea10cSStéphane Rochoy .enable_ldn = 0x08, 3238e6ea10cSStéphane Rochoy .enable_reg = 0x30, 3248e6ea10cSStéphane Rochoy .enable_mask = 0x02, 3258e6ea10cSStéphane Rochoy .data_ldn = 0x08, 3268e6ea10cSStéphane Rochoy .ppod_reg = 0xe0, /* FIXME Need to check for this group. */ 3278e6ea10cSStéphane Rochoy .caps = NCT_GPIO_CAPS, 3288e6ea10cSStéphane Rochoy .npins = 8, 3298e6ea10cSStéphane Rochoy .iobase = 0xe0, 3308e6ea10cSStéphane Rochoy }, 3318e6ea10cSStéphane Rochoy { 3328e6ea10cSStéphane Rochoy .grpnum = 1, 3338e6ea10cSStéphane Rochoy .pinbits = { 0, 1, 2, 3, 4, 5, 6, 7 }, 3348e6ea10cSStéphane Rochoy .enable_ldn = 0x08, 3358e6ea10cSStéphane Rochoy .enable_reg = 0x30, 3368e6ea10cSStéphane Rochoy .enable_mask = 0x80, 3378e6ea10cSStéphane Rochoy .data_ldn = 0x08, 3388e6ea10cSStéphane Rochoy .ppod_reg = 0xe1, /* FIXME Need to check for this group. */ 3398e6ea10cSStéphane Rochoy .caps = NCT_GPIO_CAPS, 3408e6ea10cSStéphane Rochoy .npins = 8, 3418e6ea10cSStéphane Rochoy .iobase = 0xf0, 3428e6ea10cSStéphane Rochoy }, 3438e6ea10cSStéphane Rochoy { 3448e6ea10cSStéphane Rochoy .grpnum = 2, 3458e6ea10cSStéphane Rochoy .pinbits = { 0, 1, 2, 3, 4, 5, 6, 7 }, 3468e6ea10cSStéphane Rochoy .enable_ldn = 0x09, 3478e6ea10cSStéphane Rochoy .enable_reg = 0x30, 3488e6ea10cSStéphane Rochoy .enable_mask = 0x01, 3498e6ea10cSStéphane Rochoy .data_ldn = 0x09, 3508e6ea10cSStéphane Rochoy .ppod_reg = 0xe1, /* FIXME Need to check for this group. */ 3518e6ea10cSStéphane Rochoy .caps = NCT_GPIO_CAPS, 3528e6ea10cSStéphane Rochoy .npins = 8, 3538e6ea10cSStéphane Rochoy .iobase = 0xe0, 3548e6ea10cSStéphane Rochoy }, 3558e6ea10cSStéphane Rochoy { 3568e6ea10cSStéphane Rochoy .grpnum = 3, 3578e6ea10cSStéphane Rochoy .pinbits = { 0, 1, 2, 3, 4, 5, 6 }, 3588e6ea10cSStéphane Rochoy .enable_ldn = 0x09, 3598e6ea10cSStéphane Rochoy .enable_reg = 0x30, 3608e6ea10cSStéphane Rochoy .enable_mask = 0x02, 3618e6ea10cSStéphane Rochoy .data_ldn = 0x09, 3628e6ea10cSStéphane Rochoy .ppod_reg = 0xe1, /* FIXME Need to check for this group. */ 3638e6ea10cSStéphane Rochoy .caps = NCT_GPIO_CAPS, 3648e6ea10cSStéphane Rochoy .npins = 7, 3658e6ea10cSStéphane Rochoy .iobase = 0xe4, 3668e6ea10cSStéphane Rochoy }, 3678e6ea10cSStéphane Rochoy { 3688e6ea10cSStéphane Rochoy .grpnum = 4, 3698e6ea10cSStéphane Rochoy .pinbits = { 0, 1, 2, 3, 4, 5, 6, 7 }, 3708e6ea10cSStéphane Rochoy .enable_ldn = 0x09, 3718e6ea10cSStéphane Rochoy .enable_reg = 0x30, 3728e6ea10cSStéphane Rochoy .enable_mask = 0x04, 3738e6ea10cSStéphane Rochoy .data_ldn = 0x09, 3748e6ea10cSStéphane Rochoy .ppod_reg = 0xe1, /* FIXME Need to check for this group. */ 3758e6ea10cSStéphane Rochoy .caps = NCT_GPIO_CAPS, 3768e6ea10cSStéphane Rochoy .npins = 8, 3778e6ea10cSStéphane Rochoy .iobase = 0xf0, /* FIXME Page 344 say "F0~F2, E8", 3788e6ea10cSStéphane Rochoy not "F0~F3". */ 3798e6ea10cSStéphane Rochoy }, 3808e6ea10cSStéphane Rochoy { 3818e6ea10cSStéphane Rochoy .grpnum = 5, 3828e6ea10cSStéphane Rochoy .pinbits = { 0, 1, 2, 3, 4, 5, 6, 7 }, 3838e6ea10cSStéphane Rochoy .enable_ldn = 0x09, 3848e6ea10cSStéphane Rochoy .enable_reg = 0x30, 3858e6ea10cSStéphane Rochoy .enable_mask = 0x08, 3868e6ea10cSStéphane Rochoy .data_ldn = 0x09, 3878e6ea10cSStéphane Rochoy .ppod_reg = 0xe1, /* FIXME Need to check for this group. */ 3888e6ea10cSStéphane Rochoy .caps = NCT_GPIO_CAPS, 3898e6ea10cSStéphane Rochoy .npins = 8, 3908e6ea10cSStéphane Rochoy .iobase = 0xf4, 3918e6ea10cSStéphane Rochoy }, 3928e6ea10cSStéphane Rochoy { 3938e6ea10cSStéphane Rochoy .grpnum = 6, 3948e6ea10cSStéphane Rochoy .pinbits = { 0, 1, 2, 3, 4, 5, 6, 7 }, 3958e6ea10cSStéphane Rochoy .enable_ldn = 0x07, 3968e6ea10cSStéphane Rochoy .enable_reg = 0x30, 3978e6ea10cSStéphane Rochoy .enable_mask = 0x01, 3988e6ea10cSStéphane Rochoy .data_ldn = 0x07, 3998e6ea10cSStéphane Rochoy .ppod_reg = 0xe1, /* FIXME Need to check for this group. */ 4008e6ea10cSStéphane Rochoy .caps = NCT_GPIO_CAPS, 4018e6ea10cSStéphane Rochoy .npins = 8, 4028e6ea10cSStéphane Rochoy .iobase = 0xf4, 4038e6ea10cSStéphane Rochoy }, 4048e6ea10cSStéphane Rochoy { 4058e6ea10cSStéphane Rochoy .grpnum = 7, 4068e6ea10cSStéphane Rochoy .pinbits = { 0, 1, 2, 3, 4, 5, 6, 7 }, 4078e6ea10cSStéphane Rochoy .enable_ldn = 0x07, 4088e6ea10cSStéphane Rochoy .enable_reg = 0x30, 4098e6ea10cSStéphane Rochoy .enable_mask = 0x02, 4108e6ea10cSStéphane Rochoy .data_ldn = 0x07, 4118e6ea10cSStéphane Rochoy .ppod_reg = 0xe1, /* FIXME Need to check for this group. */ 4128e6ea10cSStéphane Rochoy .caps = NCT_GPIO_CAPS, 4138e6ea10cSStéphane Rochoy .npins = 8, 4148e6ea10cSStéphane Rochoy .iobase = 0xe0, 4158e6ea10cSStéphane Rochoy }, 4168e6ea10cSStéphane Rochoy { 4178e6ea10cSStéphane Rochoy .grpnum = 8, 4188e6ea10cSStéphane Rochoy .pinbits = { 0, 1, 2, 3, 4, 5, 6, 7 }, 4198e6ea10cSStéphane Rochoy .enable_ldn = 0x07, 4208e6ea10cSStéphane Rochoy .enable_reg = 0x30, 4218e6ea10cSStéphane Rochoy .enable_mask = 0x04, 4228e6ea10cSStéphane Rochoy .data_ldn = 0x07, 4238e6ea10cSStéphane Rochoy .ppod_reg = 0xe1, /* FIXME Need to check for this group. */ 4248e6ea10cSStéphane Rochoy .caps = NCT_GPIO_CAPS, 4258e6ea10cSStéphane Rochoy .npins = 8, 4268e6ea10cSStéphane Rochoy .iobase = 0xe4, 4278e6ea10cSStéphane Rochoy }, 4288e6ea10cSStéphane Rochoy { 4298e6ea10cSStéphane Rochoy .grpnum = 9, 4308e6ea10cSStéphane Rochoy .pinbits = { 0, 1, 2, 3 }, 4318e6ea10cSStéphane Rochoy .enable_ldn = 0x07, 4328e6ea10cSStéphane Rochoy .enable_reg = 0x30, 4338e6ea10cSStéphane Rochoy .enable_mask = 0x08, 4348e6ea10cSStéphane Rochoy .data_ldn = 0x07, 4358e6ea10cSStéphane Rochoy .ppod_reg = 0xe1, /* FIXME Need to check for this group. */ 4368e6ea10cSStéphane Rochoy .caps = NCT_GPIO_CAPS, 4378e6ea10cSStéphane Rochoy .npins = 4, 4388e6ea10cSStéphane Rochoy .iobase = 0xe8, 4398e6ea10cSStéphane Rochoy }, 4408e6ea10cSStéphane Rochoy }, 4418e6ea10cSStéphane Rochoy }, 4428e6ea10cSStéphane Rochoy { 4438e6ea10cSStéphane Rochoy .devid = 0xd42a, 4448e6ea10cSStéphane Rochoy .extid = 2, 4458e6ea10cSStéphane Rochoy .descr = "GPIO on Nuvoton NCT5585D", 4468e6ea10cSStéphane Rochoy .ngroups = 6, 4478e6ea10cSStéphane Rochoy .groups = { 4488e6ea10cSStéphane Rochoy { 4498e6ea10cSStéphane Rochoy .grpnum = 2, 4508e6ea10cSStéphane Rochoy .pinbits = { 0, 1, 2, 3, 4, 5, 6 }, 4518e6ea10cSStéphane Rochoy .enable_ldn = 0x09, 4528e6ea10cSStéphane Rochoy .enable_reg = 0x30, 4538e6ea10cSStéphane Rochoy .enable_mask = 0x01, 4548e6ea10cSStéphane Rochoy .data_ldn = 0x09, 4558e6ea10cSStéphane Rochoy .ppod_reg = 0xe1, 4568e6ea10cSStéphane Rochoy .caps = NCT_GPIO_CAPS, 4578e6ea10cSStéphane Rochoy .npins = 7, 4588e6ea10cSStéphane Rochoy .iobase = 0xe0, 4598e6ea10cSStéphane Rochoy }, 4608e6ea10cSStéphane Rochoy { 4618e6ea10cSStéphane Rochoy .grpnum = 3, 4628e6ea10cSStéphane Rochoy .pinbits = { 1, 2, 3 }, 4638e6ea10cSStéphane Rochoy .enable_ldn = 0x09, 4648e6ea10cSStéphane Rochoy .enable_reg = 0x30, 4658e6ea10cSStéphane Rochoy .enable_mask = 0x02, 4668e6ea10cSStéphane Rochoy .data_ldn = 0x09, 4678e6ea10cSStéphane Rochoy .ppod_reg = 0xe2, 4688e6ea10cSStéphane Rochoy .caps = NCT_GPIO_CAPS, 4698e6ea10cSStéphane Rochoy .npins = 3, 4708e6ea10cSStéphane Rochoy .iobase = 0xe4, 4718e6ea10cSStéphane Rochoy }, 4728e6ea10cSStéphane Rochoy { 4738e6ea10cSStéphane Rochoy .grpnum = 5, 4748e6ea10cSStéphane Rochoy .pinbits = { 0, 2, 6, 7 }, 4758e6ea10cSStéphane Rochoy .enable_ldn = 0x09, 4768e6ea10cSStéphane Rochoy .enable_reg = 0x30, 4778e6ea10cSStéphane Rochoy .enable_mask = 0x08, 4788e6ea10cSStéphane Rochoy .data_ldn = 0x09, 4798e6ea10cSStéphane Rochoy .ppod_reg = 0xe4, 4808e6ea10cSStéphane Rochoy .caps = NCT_GPIO_CAPS, 4818e6ea10cSStéphane Rochoy .npins = 4, 4828e6ea10cSStéphane Rochoy .iobase = 0xf4, 4838e6ea10cSStéphane Rochoy }, 4848e6ea10cSStéphane Rochoy { 4858e6ea10cSStéphane Rochoy .grpnum = 7, 4868e6ea10cSStéphane Rochoy .pinbits = { 4 }, 4878e6ea10cSStéphane Rochoy .enable_ldn = 0x07, 4888e6ea10cSStéphane Rochoy .enable_reg = 0x30, 4898e6ea10cSStéphane Rochoy .enable_mask = 0x02, 4908e6ea10cSStéphane Rochoy .data_ldn = 0x07, 4918e6ea10cSStéphane Rochoy .ppod_reg = 0xe6, 4928e6ea10cSStéphane Rochoy .caps = NCT_GPIO_CAPS, 4938e6ea10cSStéphane Rochoy .npins = 1, 4948e6ea10cSStéphane Rochoy .iobase = 0xe0, 4958e6ea10cSStéphane Rochoy }, 4968e6ea10cSStéphane Rochoy { 4978e6ea10cSStéphane Rochoy .grpnum = 8, 4988e6ea10cSStéphane Rochoy .pinbits = { 0, 1, 2, 3, 4, 5, 6, 7 }, 4998e6ea10cSStéphane Rochoy .enable_ldn = 0x07, 5008e6ea10cSStéphane Rochoy .enable_reg = 0x30, 5018e6ea10cSStéphane Rochoy .enable_mask = 0x04, 5028e6ea10cSStéphane Rochoy .data_ldn = 0x07, 5038e6ea10cSStéphane Rochoy .ppod_reg = 0xe7, 5048e6ea10cSStéphane Rochoy .caps = NCT_GPIO_CAPS, 5058e6ea10cSStéphane Rochoy .npins = 8, 5068e6ea10cSStéphane Rochoy .iobase = 0xe4, 5078e6ea10cSStéphane Rochoy }, 5088e6ea10cSStéphane Rochoy { 5098e6ea10cSStéphane Rochoy .grpnum = 9, 5108e6ea10cSStéphane Rochoy .pinbits = { 0, 2 }, 5118e6ea10cSStéphane Rochoy .enable_ldn = 0x07, 5128e6ea10cSStéphane Rochoy .enable_reg = 0x30, 5138e6ea10cSStéphane Rochoy .enable_mask = 0x08, 5148e6ea10cSStéphane Rochoy .data_ldn = 0x07, 5158e6ea10cSStéphane Rochoy .ppod_reg = 0xea, 5168e6ea10cSStéphane Rochoy .caps = NCT_GPIO_CAPS, 5178e6ea10cSStéphane Rochoy .npins = 2, 5188e6ea10cSStéphane Rochoy .iobase = 0xe8, 5198e6ea10cSStéphane Rochoy }, 5208e6ea10cSStéphane Rochoy }, 5218e6ea10cSStéphane Rochoy }, 5228e6ea10cSStéphane Rochoy { 5238e6ea10cSStéphane Rochoy .devid = 0xc562, 5248e6ea10cSStéphane Rochoy .descr = "GPIO on Nuvoton NCT6779D", 5258e6ea10cSStéphane Rochoy .ngroups = 9, 5268e6ea10cSStéphane Rochoy .groups = { 5278e6ea10cSStéphane Rochoy { 5288e6ea10cSStéphane Rochoy .grpnum = 0, 5298e6ea10cSStéphane Rochoy .pinbits = { 0, 1, 2, 3, 4, 5, 6, 7 }, 5308e6ea10cSStéphane Rochoy .enable_ldn = 0x08, 5318e6ea10cSStéphane Rochoy .enable_reg = 0x30, 5328e6ea10cSStéphane Rochoy .enable_mask = 0x01, 5338e6ea10cSStéphane Rochoy .data_ldn = 0x08, 5348e6ea10cSStéphane Rochoy .ppod_reg = 0xe0, /* FIXME Need to check for this group. */ 5358e6ea10cSStéphane Rochoy .caps = NCT_GPIO_CAPS, 5368e6ea10cSStéphane Rochoy .npins = 8, 5378e6ea10cSStéphane Rochoy .iobase = 0xe0, 5388e6ea10cSStéphane Rochoy }, 5398e6ea10cSStéphane Rochoy { 5408e6ea10cSStéphane Rochoy .grpnum = 1, 5418e6ea10cSStéphane Rochoy .pinbits = { 0, 1, 2, 3, 4, 5, 6, 7 }, 5428e6ea10cSStéphane Rochoy .enable_ldn = 0x09, 5438e6ea10cSStéphane Rochoy .enable_reg = 0x30, 5448e6ea10cSStéphane Rochoy .enable_mask = 0x01, 5458e6ea10cSStéphane Rochoy .data_ldn = 0x08, 5468e6ea10cSStéphane Rochoy .ppod_reg = 0xe1, /* FIXME Need to check for this group. */ 5478e6ea10cSStéphane Rochoy .caps = NCT_GPIO_CAPS, 5488e6ea10cSStéphane Rochoy .npins = 8, 5498e6ea10cSStéphane Rochoy .iobase = 0xf0, 5508e6ea10cSStéphane Rochoy }, 5518e6ea10cSStéphane Rochoy { 5528e6ea10cSStéphane Rochoy .grpnum = 2, 5538e6ea10cSStéphane Rochoy .pinbits = { 0, 1, 2, 3, 4, 5, 6, 7 }, 5548e6ea10cSStéphane Rochoy .enable_ldn = 0x09, 5558e6ea10cSStéphane Rochoy .enable_reg = 0x30, 5568e6ea10cSStéphane Rochoy .enable_mask = 0x01, 5578e6ea10cSStéphane Rochoy .data_ldn = 0x09, 5588e6ea10cSStéphane Rochoy .ppod_reg = 0xe1, /* FIXME Need to check for this group. */ 5598e6ea10cSStéphane Rochoy .caps = NCT_GPIO_CAPS, 5608e6ea10cSStéphane Rochoy .npins = 8, 5618e6ea10cSStéphane Rochoy .iobase = 0xe0, 5628e6ea10cSStéphane Rochoy }, 5638e6ea10cSStéphane Rochoy { 5648e6ea10cSStéphane Rochoy .grpnum = 3, 5658e6ea10cSStéphane Rochoy .pinbits = { 0, 1, 2, 3, 4, 5, 6 }, 5668e6ea10cSStéphane Rochoy .enable_ldn = 0x09, 5678e6ea10cSStéphane Rochoy .enable_reg = 0x30, 5688e6ea10cSStéphane Rochoy .enable_mask = 0x02, 5698e6ea10cSStéphane Rochoy .data_ldn = 0x09, 5708e6ea10cSStéphane Rochoy .ppod_reg = 0xe1, /* FIXME Need to check for this group. */ 5718e6ea10cSStéphane Rochoy .caps = NCT_GPIO_CAPS, 5728e6ea10cSStéphane Rochoy .npins = 7, 5738e6ea10cSStéphane Rochoy .iobase = 0xe4, 5748e6ea10cSStéphane Rochoy }, 5758e6ea10cSStéphane Rochoy { 5768e6ea10cSStéphane Rochoy .grpnum = 4, 5778e6ea10cSStéphane Rochoy .pinbits = { 0, 1, 2, 3, 4, 5, 6, 7 }, 5788e6ea10cSStéphane Rochoy .enable_ldn = 0x09, 5798e6ea10cSStéphane Rochoy .enable_reg = 0x30, 5808e6ea10cSStéphane Rochoy .enable_mask = 0x04, 5818e6ea10cSStéphane Rochoy .data_ldn = 0x09, 5828e6ea10cSStéphane Rochoy .ppod_reg = 0xe1, /* FIXME Need to check for this group. */ 5838e6ea10cSStéphane Rochoy .caps = NCT_GPIO_CAPS, 5848e6ea10cSStéphane Rochoy .npins = 8, 5858e6ea10cSStéphane Rochoy .iobase = 0xf0, 5868e6ea10cSStéphane Rochoy }, 5878e6ea10cSStéphane Rochoy { 5888e6ea10cSStéphane Rochoy .grpnum = 5, 5898e6ea10cSStéphane Rochoy .pinbits = { 0, 1, 2, 3, 4, 5, 6, 7 }, 5908e6ea10cSStéphane Rochoy .enable_ldn = 0x09, 5918e6ea10cSStéphane Rochoy .enable_reg = 0x30, 5928e6ea10cSStéphane Rochoy .enable_mask = 0x08, 5938e6ea10cSStéphane Rochoy .data_ldn = 0x09, 5948e6ea10cSStéphane Rochoy .ppod_reg = 0xe1, /* FIXME Need to check for this group. */ 5958e6ea10cSStéphane Rochoy .caps = NCT_GPIO_CAPS, 5968e6ea10cSStéphane Rochoy .npins = 8, 5978e6ea10cSStéphane Rochoy .iobase = 0xf4, 5988e6ea10cSStéphane Rochoy }, 5998e6ea10cSStéphane Rochoy { 6008e6ea10cSStéphane Rochoy .grpnum = 6, 6018e6ea10cSStéphane Rochoy .pinbits = { 0, 1, 2, 3, 4, 5, 6, 7 }, 6028e6ea10cSStéphane Rochoy .enable_ldn = 0x09, 6038e6ea10cSStéphane Rochoy .enable_reg = 0x30, 6048e6ea10cSStéphane Rochoy .enable_mask = 0x01, 6058e6ea10cSStéphane Rochoy .data_ldn = 0x07, 6068e6ea10cSStéphane Rochoy .ppod_reg = 0xe1, /* FIXME Need to check for this group. */ 6078e6ea10cSStéphane Rochoy .caps = NCT_GPIO_CAPS, 6088e6ea10cSStéphane Rochoy .npins = 8, 6098e6ea10cSStéphane Rochoy .iobase = 0xf4, 6108e6ea10cSStéphane Rochoy }, 6118e6ea10cSStéphane Rochoy { 6128e6ea10cSStéphane Rochoy .grpnum = 7, 6138e6ea10cSStéphane Rochoy .pinbits = { 0, 1, 2, 3, 4, 5, 6 }, 6148e6ea10cSStéphane Rochoy .enable_ldn = 0x09, 6158e6ea10cSStéphane Rochoy .enable_reg = 0x30, 6168e6ea10cSStéphane Rochoy .enable_mask = 0x02, 6178e6ea10cSStéphane Rochoy .data_ldn = 0x07, 6188e6ea10cSStéphane Rochoy .ppod_reg = 0xe1, /* FIXME Need to check for this group. */ 6198e6ea10cSStéphane Rochoy .caps = NCT_GPIO_CAPS, 6208e6ea10cSStéphane Rochoy .npins = 7, 6218e6ea10cSStéphane Rochoy .iobase = 0xe0, 6228e6ea10cSStéphane Rochoy }, 6238e6ea10cSStéphane Rochoy { 6248e6ea10cSStéphane Rochoy .grpnum = 8, 6258e6ea10cSStéphane Rochoy .pinbits = { 0, 1, 2, 3, 4, 5, 6, 7 }, 6268e6ea10cSStéphane Rochoy .enable_ldn = 0x09, 6278e6ea10cSStéphane Rochoy .enable_reg = 0x30, 6288e6ea10cSStéphane Rochoy .enable_mask = 0x04, 6298e6ea10cSStéphane Rochoy .data_ldn = 0x07, 6308e6ea10cSStéphane Rochoy .ppod_reg = 0xe1, /* FIXME Need to check for this group. */ 6318e6ea10cSStéphane Rochoy .caps = NCT_GPIO_CAPS, 6328e6ea10cSStéphane Rochoy .npins = 8, 6338e6ea10cSStéphane Rochoy .iobase = 0xe4, 6348e6ea10cSStéphane Rochoy }, 6358e6ea10cSStéphane Rochoy }, 6368e6ea10cSStéphane Rochoy }, 6378e6ea10cSStéphane Rochoy { 6388e6ea10cSStéphane Rochoy .devid = 0xd282, 6398e6ea10cSStéphane Rochoy .descr = "GPIO on Nuvoton NCT6112D/NCT6114D/NCT6116D", 640*8e4aa631SStéphane Rochoy .ngroups = 9, 6418e6ea10cSStéphane Rochoy .groups = { 6428e6ea10cSStéphane Rochoy { 6438e6ea10cSStéphane Rochoy .grpnum = 0, 6448e6ea10cSStéphane Rochoy .pinbits = { 0, 1, 2, 3, 4, 5, 6, 7 }, 6458e6ea10cSStéphane Rochoy .enable_ldn = 0x07, 6468e6ea10cSStéphane Rochoy .enable_reg = 0x30, 6478e6ea10cSStéphane Rochoy .enable_mask = 0x01, 6488e6ea10cSStéphane Rochoy .data_ldn = 0x07, 649*8e4aa631SStéphane Rochoy .ppod_reg = 0xe0, 6508e6ea10cSStéphane Rochoy .caps = NCT_GPIO_CAPS, 6518e6ea10cSStéphane Rochoy .npins = 8, 6528e6ea10cSStéphane Rochoy .iobase = 0xe0, 6538e6ea10cSStéphane Rochoy }, 6548e6ea10cSStéphane Rochoy { 6558e6ea10cSStéphane Rochoy .grpnum = 1, 6568e6ea10cSStéphane Rochoy .pinbits = { 0, 1, 2, 3, 4, 5, 6, 7 }, 6578e6ea10cSStéphane Rochoy .enable_ldn = 0x07, 6588e6ea10cSStéphane Rochoy .enable_reg = 0x30, 6598e6ea10cSStéphane Rochoy .enable_mask = 0x02, 6608e6ea10cSStéphane Rochoy .data_ldn = 0x07, 661*8e4aa631SStéphane Rochoy .ppod_reg = 0xe1, 6628e6ea10cSStéphane Rochoy .caps = NCT_GPIO_CAPS, 6638e6ea10cSStéphane Rochoy .npins = 8, 6648e6ea10cSStéphane Rochoy .iobase = 0xe4, 6658e6ea10cSStéphane Rochoy }, 6668e6ea10cSStéphane Rochoy { 6678e6ea10cSStéphane Rochoy .grpnum = 2, 6688e6ea10cSStéphane Rochoy .pinbits = { 0, 1, 2, 3, 4, 5, 6, 7 }, 6698e6ea10cSStéphane Rochoy .enable_ldn = 0x07, 6708e6ea10cSStéphane Rochoy .enable_reg = 0x30, 6718e6ea10cSStéphane Rochoy .enable_mask = 0x04, 6728e6ea10cSStéphane Rochoy .data_ldn = 0x07, 673*8e4aa631SStéphane Rochoy .ppod_reg = 0xe1, 6748e6ea10cSStéphane Rochoy .caps = NCT_GPIO_CAPS, 6758e6ea10cSStéphane Rochoy .npins = 8, 6768e6ea10cSStéphane Rochoy .iobase = 0xe8, 6778e6ea10cSStéphane Rochoy }, 6788e6ea10cSStéphane Rochoy { 6798e6ea10cSStéphane Rochoy .grpnum = 3, 6808e6ea10cSStéphane Rochoy .pinbits = { 0, 1, 2, 3, 4, 5, 6, 7 }, 6818e6ea10cSStéphane Rochoy .enable_ldn = 0x07, 6828e6ea10cSStéphane Rochoy .enable_reg = 0x30, 6838e6ea10cSStéphane Rochoy .enable_mask = 0x08, 6848e6ea10cSStéphane Rochoy .data_ldn = 0x07, 685*8e4aa631SStéphane Rochoy .ppod_reg = 0xe1, 6868e6ea10cSStéphane Rochoy .caps = NCT_GPIO_CAPS, 6878e6ea10cSStéphane Rochoy .npins = 8, 6888e6ea10cSStéphane Rochoy .iobase = 0xec, 6898e6ea10cSStéphane Rochoy }, 6908e6ea10cSStéphane Rochoy { 6918e6ea10cSStéphane Rochoy .grpnum = 4, 6928e6ea10cSStéphane Rochoy .pinbits = { 0, 1, 2, 3, 4, 5, 6, 7 }, 6938e6ea10cSStéphane Rochoy .enable_ldn = 0x07, 6948e6ea10cSStéphane Rochoy .enable_reg = 0x30, 6958e6ea10cSStéphane Rochoy .enable_mask = 0x10, 6968e6ea10cSStéphane Rochoy .data_ldn = 0x07, 697*8e4aa631SStéphane Rochoy .ppod_reg = 0xe1, 6988e6ea10cSStéphane Rochoy .caps = NCT_GPIO_CAPS, 6998e6ea10cSStéphane Rochoy .npins = 8, 7008e6ea10cSStéphane Rochoy .iobase = 0xf0, 7018e6ea10cSStéphane Rochoy }, 7028e6ea10cSStéphane Rochoy { 7038e6ea10cSStéphane Rochoy .grpnum = 5, 7048e6ea10cSStéphane Rochoy .pinbits = { 0, 1, 2, 3, 4, 5, 6, 7 }, 7058e6ea10cSStéphane Rochoy .enable_ldn = 0x07, 7068e6ea10cSStéphane Rochoy .enable_reg = 0x30, 7078e6ea10cSStéphane Rochoy .enable_mask = 0x20, 7088e6ea10cSStéphane Rochoy .data_ldn = 0x07, 709*8e4aa631SStéphane Rochoy .ppod_reg = 0xe1, 7108e6ea10cSStéphane Rochoy .caps = NCT_GPIO_CAPS, 7118e6ea10cSStéphane Rochoy .npins = 8, 7128e6ea10cSStéphane Rochoy .iobase = 0xf4, 7138e6ea10cSStéphane Rochoy }, 7148e6ea10cSStéphane Rochoy { 7158e6ea10cSStéphane Rochoy .grpnum = 6, 7168e6ea10cSStéphane Rochoy .pinbits = { 0, 1, 2, 3, 4, 5, 6, 7 }, 7178e6ea10cSStéphane Rochoy .enable_ldn = 0x07, 7188e6ea10cSStéphane Rochoy .enable_reg = 0x30, 7198e6ea10cSStéphane Rochoy .enable_mask = 0x40, 7208e6ea10cSStéphane Rochoy .data_ldn = 0x07, 721*8e4aa631SStéphane Rochoy .ppod_reg = 0xe1, 7228e6ea10cSStéphane Rochoy .caps = NCT_GPIO_CAPS, 7238e6ea10cSStéphane Rochoy .npins = 8, 7248e6ea10cSStéphane Rochoy .iobase = 0xf8, 7258e6ea10cSStéphane Rochoy }, 7268e6ea10cSStéphane Rochoy { 7278e6ea10cSStéphane Rochoy .grpnum = 7, 7288e6ea10cSStéphane Rochoy .pinbits = { 0, 1, 2, 3, 4, 5, 6, 7 }, 7298e6ea10cSStéphane Rochoy .enable_ldn = 0x07, 7308e6ea10cSStéphane Rochoy .enable_reg = 0x30, 7318e6ea10cSStéphane Rochoy .enable_mask = 0x80, 7328e6ea10cSStéphane Rochoy .data_ldn = 0x07, 733*8e4aa631SStéphane Rochoy .ppod_reg = 0xe1, 7348e6ea10cSStéphane Rochoy .caps = NCT_GPIO_CAPS, 7358e6ea10cSStéphane Rochoy .npins = 8, 7368e6ea10cSStéphane Rochoy .iobase = 0xfc, 7378e6ea10cSStéphane Rochoy }, 7388e6ea10cSStéphane Rochoy { 7398e6ea10cSStéphane Rochoy .grpnum = 8, 7408e6ea10cSStéphane Rochoy .pinbits = { 0, 1, 2, 3, 4, 5, 6, 7 }, 7418e6ea10cSStéphane Rochoy .enable_ldn = 0x09, 7428e6ea10cSStéphane Rochoy .enable_reg = 0x30, 7438e6ea10cSStéphane Rochoy .enable_mask = 0x01, 7448e6ea10cSStéphane Rochoy .data_ldn = 0x09, 745*8e4aa631SStéphane Rochoy .ppod_reg = 0xe1, 7468e6ea10cSStéphane Rochoy .caps = NCT_GPIO_CAPS, 7478e6ea10cSStéphane Rochoy .npins = 8, 7488e6ea10cSStéphane Rochoy .iobase = 0xf0, 7498e6ea10cSStéphane Rochoy }, 7508e6ea10cSStéphane Rochoy }, 7518e6ea10cSStéphane Rochoy }, 7526b7b2d80SAdrian Chadd }; 7536b7b2d80SAdrian Chadd 7547f8d2ed0SStéphane Rochoy static const char * 7557f8d2ed0SStéphane Rochoy io2str(uint8_t ioport) 7566b7b2d80SAdrian Chadd { 7577f8d2ed0SStéphane Rochoy switch (ioport) { 7587f8d2ed0SStéphane Rochoy case NCT_IO_GSR: return ("grpsel"); 7597f8d2ed0SStéphane Rochoy case NCT_IO_IOR: return ("io"); 7607f8d2ed0SStéphane Rochoy case NCT_IO_DAT: return ("data"); 7617f8d2ed0SStéphane Rochoy case NCT_IO_INV: return ("inv"); 7627f8d2ed0SStéphane Rochoy case NCT_IO_DST: return ("status"); 7637f8d2ed0SStéphane Rochoy default: return ("?"); 7647f8d2ed0SStéphane Rochoy } 7657f8d2ed0SStéphane Rochoy } 7666b7b2d80SAdrian Chadd 7677f8d2ed0SStéphane Rochoy static void 7687f8d2ed0SStéphane Rochoy nct_io_set_group(struct nct_softc *sc, uint8_t grpnum) 7697f8d2ed0SStéphane Rochoy { 770155514eaSAndriy Gapon GPIO_ASSERT_LOCKED(sc); 7717f8d2ed0SStéphane Rochoy 7727f8d2ed0SStéphane Rochoy if (grpnum == sc->curgrp) 7737f8d2ed0SStéphane Rochoy return; 7747f8d2ed0SStéphane Rochoy 7757f8d2ed0SStéphane Rochoy NCT_VERBOSE_PRINTF(sc->dev, "write %s 0x%x ioport %d\n", 7767f8d2ed0SStéphane Rochoy io2str(NCT_IO_GSR), grpnum, NCT_IO_GSR); 7777f8d2ed0SStéphane Rochoy bus_write_1(sc->iores, NCT_IO_GSR, grpnum); 7787f8d2ed0SStéphane Rochoy sc->curgrp = grpnum; 779155514eaSAndriy Gapon } 7806b7b2d80SAdrian Chadd 781155514eaSAndriy Gapon static uint8_t 7827f8d2ed0SStéphane Rochoy nct_io_read(struct nct_softc *sc, uint8_t grpnum, uint8_t reg) 783155514eaSAndriy Gapon { 784155514eaSAndriy Gapon uint8_t val; 785155514eaSAndriy Gapon 7867f8d2ed0SStéphane Rochoy nct_io_set_group(sc, grpnum); 787155514eaSAndriy Gapon 7887f8d2ed0SStéphane Rochoy val = bus_read_1(sc->iores, reg); 7897f8d2ed0SStéphane Rochoy NCT_VERBOSE_PRINTF(sc->dev, "read %s 0x%x ioport %d\n", 7907f8d2ed0SStéphane Rochoy io2str(reg), val, reg); 791155514eaSAndriy Gapon return (val); 792155514eaSAndriy Gapon } 793155514eaSAndriy Gapon 7947f8d2ed0SStéphane Rochoy static void 7957f8d2ed0SStéphane Rochoy nct_io_write(struct nct_softc *sc, uint8_t grpnum, uint8_t reg, uint8_t val) 796155514eaSAndriy Gapon { 7977f8d2ed0SStéphane Rochoy nct_io_set_group(sc, grpnum); 7987f8d2ed0SStéphane Rochoy 7997f8d2ed0SStéphane Rochoy NCT_VERBOSE_PRINTF(sc->dev, "write %s 0x%x ioport %d\n", 8007f8d2ed0SStéphane Rochoy io2str(reg), val, reg); 8017f8d2ed0SStéphane Rochoy bus_write_1(sc->iores, reg, val); 8027f8d2ed0SStéphane Rochoy } 8037f8d2ed0SStéphane Rochoy 8047f8d2ed0SStéphane Rochoy static uint8_t 8057f8d2ed0SStéphane Rochoy nct_get_ioreg(struct nct_softc *sc, reg_t reg, uint8_t grpnum) 8067f8d2ed0SStéphane Rochoy { 8077f8d2ed0SStéphane Rochoy uint8_t iobase; 8087f8d2ed0SStéphane Rochoy 8097f8d2ed0SStéphane Rochoy if (sc->iores != NULL) 8107f8d2ed0SStéphane Rochoy iobase = NCT_IO_IOR; 8117f8d2ed0SStéphane Rochoy else 8127f8d2ed0SStéphane Rochoy iobase = sc->grpmap[grpnum]->iobase; 8137f8d2ed0SStéphane Rochoy return (iobase + reg); 8147f8d2ed0SStéphane Rochoy } 8157f8d2ed0SStéphane Rochoy 8167f8d2ed0SStéphane Rochoy static const char * 8177f8d2ed0SStéphane Rochoy reg2str(reg_t reg) 8187f8d2ed0SStéphane Rochoy { 8197f8d2ed0SStéphane Rochoy switch (reg) { 8207f8d2ed0SStéphane Rochoy case REG_IOR: return ("io"); 8217f8d2ed0SStéphane Rochoy case REG_DAT: return ("data"); 8227f8d2ed0SStéphane Rochoy case REG_INV: return ("inv"); 8237f8d2ed0SStéphane Rochoy default: return ("?"); 8247f8d2ed0SStéphane Rochoy } 8257f8d2ed0SStéphane Rochoy } 8267f8d2ed0SStéphane Rochoy 8277f8d2ed0SStéphane Rochoy static uint8_t 8287f8d2ed0SStéphane Rochoy nct_read_reg(struct nct_softc *sc, reg_t reg, uint8_t grpnum) 8297f8d2ed0SStéphane Rochoy { 8307f8d2ed0SStéphane Rochoy struct nct_gpio_group *gp; 8317f8d2ed0SStéphane Rochoy uint8_t ioreg; 832155514eaSAndriy Gapon uint8_t val; 833155514eaSAndriy Gapon 8347f8d2ed0SStéphane Rochoy ioreg = nct_get_ioreg(sc, reg, grpnum); 835155514eaSAndriy Gapon 8367f8d2ed0SStéphane Rochoy if (sc->iores != NULL) 8377f8d2ed0SStéphane Rochoy return (nct_io_read(sc, grpnum, ioreg)); 8387f8d2ed0SStéphane Rochoy 8397f8d2ed0SStéphane Rochoy gp = sc->grpmap[grpnum]; 8407f8d2ed0SStéphane Rochoy val = superio_ldn_read(sc->dev, gp->data_ldn, ioreg); 8417f8d2ed0SStéphane Rochoy NCT_VERBOSE_PRINTF(sc->dev, "read %s 0x%x from group GPIO%u ioreg 0x%x\n", 8427f8d2ed0SStéphane Rochoy reg2str(reg), val, grpnum, ioreg); 8437f8d2ed0SStéphane Rochoy return (val); 844155514eaSAndriy Gapon } 845155514eaSAndriy Gapon 846155514eaSAndriy Gapon static int 847155514eaSAndriy Gapon nct_get_pin_cache(struct nct_softc *sc, uint32_t pin_num, uint8_t *cache) 848155514eaSAndriy Gapon { 849155514eaSAndriy Gapon uint8_t bit; 850155514eaSAndriy Gapon uint8_t group; 851155514eaSAndriy Gapon uint8_t val; 852155514eaSAndriy Gapon 8537f8d2ed0SStéphane Rochoy KASSERT(NCT_PIN_IS_VALID(sc, pin_num), ("%s: invalid pin number %d", 854155514eaSAndriy Gapon __func__, pin_num)); 855155514eaSAndriy Gapon 8567f8d2ed0SStéphane Rochoy group = NCT_PIN_GRPNUM(sc, pin_num); 8577f8d2ed0SStéphane Rochoy bit = NCT_PIN_BIT(sc, pin_num); 858155514eaSAndriy Gapon val = cache[group]; 859155514eaSAndriy Gapon return (GET_BIT(val, bit)); 860155514eaSAndriy Gapon } 861155514eaSAndriy Gapon 862155514eaSAndriy Gapon static void 8637f8d2ed0SStéphane Rochoy nct_write_reg(struct nct_softc *sc, reg_t reg, uint8_t grpnum, uint8_t val) 864155514eaSAndriy Gapon { 8657f8d2ed0SStéphane Rochoy struct nct_gpio_group *gp; 866155514eaSAndriy Gapon uint8_t ioreg; 867155514eaSAndriy Gapon 8687f8d2ed0SStéphane Rochoy ioreg = nct_get_ioreg(sc, reg, grpnum); 8697f8d2ed0SStéphane Rochoy 8707f8d2ed0SStéphane Rochoy if (sc->iores != NULL) { 8717f8d2ed0SStéphane Rochoy nct_io_write(sc, grpnum, ioreg, val); 8727f8d2ed0SStéphane Rochoy return; 8737f8d2ed0SStéphane Rochoy } 8747f8d2ed0SStéphane Rochoy 8757f8d2ed0SStéphane Rochoy gp = sc->grpmap[grpnum]; 8767f8d2ed0SStéphane Rochoy superio_ldn_write(sc->dev, gp->data_ldn, ioreg, val); 8777f8d2ed0SStéphane Rochoy 8787f8d2ed0SStéphane Rochoy NCT_VERBOSE_PRINTF(sc->dev, "write %s 0x%x to group GPIO%u ioreg 0x%x\n", 8797f8d2ed0SStéphane Rochoy reg2str(reg), val, grpnum, ioreg); 880155514eaSAndriy Gapon } 881155514eaSAndriy Gapon 882155514eaSAndriy Gapon static void 883155514eaSAndriy Gapon nct_set_pin_reg(struct nct_softc *sc, reg_t reg, uint32_t pin_num, bool val) 884155514eaSAndriy Gapon { 885155514eaSAndriy Gapon uint8_t *cache; 886155514eaSAndriy Gapon uint8_t bit; 887155514eaSAndriy Gapon uint8_t bitval; 888155514eaSAndriy Gapon uint8_t group; 889155514eaSAndriy Gapon uint8_t mask; 890155514eaSAndriy Gapon 8917f8d2ed0SStéphane Rochoy KASSERT(NCT_PIN_IS_VALID(sc, pin_num), 892155514eaSAndriy Gapon ("%s: invalid pin number %d", __func__, pin_num)); 893155514eaSAndriy Gapon KASSERT(reg == REG_IOR || reg == REG_INV, 894155514eaSAndriy Gapon ("%s: unsupported register %d", __func__, reg)); 895155514eaSAndriy Gapon 8967f8d2ed0SStéphane Rochoy group = NCT_PIN_GRPNUM(sc, pin_num); 8977f8d2ed0SStéphane Rochoy bit = NCT_PIN_BIT(sc, pin_num); 898155514eaSAndriy Gapon mask = (uint8_t)1 << bit; 899155514eaSAndriy Gapon bitval = (uint8_t)val << bit; 900155514eaSAndriy Gapon 901155514eaSAndriy Gapon if (reg == REG_IOR) 902155514eaSAndriy Gapon cache = &sc->cache.ior[group]; 903155514eaSAndriy Gapon else 904155514eaSAndriy Gapon cache = &sc->cache.inv[group]; 905155514eaSAndriy Gapon if ((*cache & mask) == bitval) 906155514eaSAndriy Gapon return; 907155514eaSAndriy Gapon *cache &= ~mask; 908155514eaSAndriy Gapon *cache |= bitval; 909155514eaSAndriy Gapon nct_write_reg(sc, reg, group, *cache); 9106b7b2d80SAdrian Chadd } 9116b7b2d80SAdrian Chadd 9126b7b2d80SAdrian Chadd /* 913155514eaSAndriy Gapon * Set a pin to input (val is true) or output (val is false) mode. 9146b7b2d80SAdrian Chadd */ 9156b7b2d80SAdrian Chadd static void 916155514eaSAndriy Gapon nct_set_pin_input(struct nct_softc *sc, uint32_t pin_num, bool val) 9176b7b2d80SAdrian Chadd { 918155514eaSAndriy Gapon nct_set_pin_reg(sc, REG_IOR, pin_num, val); 9196b7b2d80SAdrian Chadd } 9206b7b2d80SAdrian Chadd 9216b7b2d80SAdrian Chadd /* 9226b7b2d80SAdrian Chadd * Check whether a pin is configured as an input. 9236b7b2d80SAdrian Chadd */ 9246b7b2d80SAdrian Chadd static bool 9256b7b2d80SAdrian Chadd nct_pin_is_input(struct nct_softc *sc, uint32_t pin_num) 9266b7b2d80SAdrian Chadd { 927155514eaSAndriy Gapon return (nct_get_pin_cache(sc, pin_num, sc->cache.ior)); 9286b7b2d80SAdrian Chadd } 9296b7b2d80SAdrian Chadd 9306b7b2d80SAdrian Chadd /* 931155514eaSAndriy Gapon * Set a pin to inverted (val is true) or normal (val is false) mode. 9326b7b2d80SAdrian Chadd */ 9336b7b2d80SAdrian Chadd static void 934155514eaSAndriy Gapon nct_set_pin_inverted(struct nct_softc *sc, uint32_t pin_num, bool val) 9356b7b2d80SAdrian Chadd { 936155514eaSAndriy Gapon nct_set_pin_reg(sc, REG_INV, pin_num, val); 9376b7b2d80SAdrian Chadd } 9386b7b2d80SAdrian Chadd 9396b7b2d80SAdrian Chadd static bool 9406b7b2d80SAdrian Chadd nct_pin_is_inverted(struct nct_softc *sc, uint32_t pin_num) 9416b7b2d80SAdrian Chadd { 942155514eaSAndriy Gapon return (nct_get_pin_cache(sc, pin_num, sc->cache.inv)); 9436b7b2d80SAdrian Chadd } 9446b7b2d80SAdrian Chadd 945155514eaSAndriy Gapon /* 946155514eaSAndriy Gapon * Write a value to an output pin. 947155514eaSAndriy Gapon * NB: the hardware remembers last output value across switching from 948155514eaSAndriy Gapon * output mode to input mode and back. 949155514eaSAndriy Gapon * Writes to a pin in input mode are not allowed here as they cannot 950155514eaSAndriy Gapon * have any effect and would corrupt the output value cache. 951155514eaSAndriy Gapon */ 952155514eaSAndriy Gapon static void 953155514eaSAndriy Gapon nct_write_pin(struct nct_softc *sc, uint32_t pin_num, bool val) 954155514eaSAndriy Gapon { 955155514eaSAndriy Gapon uint8_t bit; 956155514eaSAndriy Gapon uint8_t group; 957155514eaSAndriy Gapon 958155514eaSAndriy Gapon KASSERT(!nct_pin_is_input(sc, pin_num), ("attempt to write input pin")); 9597f8d2ed0SStéphane Rochoy group = NCT_PIN_GRPNUM(sc, pin_num); 9607f8d2ed0SStéphane Rochoy bit = NCT_PIN_BIT(sc, pin_num); 9617f8d2ed0SStéphane Rochoy 962155514eaSAndriy Gapon if (GET_BIT(sc->cache.out_known[group], bit) && 963155514eaSAndriy Gapon GET_BIT(sc->cache.out[group], bit) == val) { 964155514eaSAndriy Gapon /* The pin is already in requested state. */ 965155514eaSAndriy Gapon return; 966155514eaSAndriy Gapon } 967155514eaSAndriy Gapon sc->cache.out_known[group] |= 1 << bit; 968155514eaSAndriy Gapon if (val) 969155514eaSAndriy Gapon sc->cache.out[group] |= 1 << bit; 970155514eaSAndriy Gapon else 971155514eaSAndriy Gapon sc->cache.out[group] &= ~(1 << bit); 972155514eaSAndriy Gapon nct_write_reg(sc, REG_DAT, group, sc->cache.out[group]); 973155514eaSAndriy Gapon } 974155514eaSAndriy Gapon 9757f8d2ed0SStéphane Rochoy static bool 9767f8d2ed0SStéphane Rochoy nct_get_pin_reg(struct nct_softc *sc, reg_t reg, uint32_t pin_num) 9777f8d2ed0SStéphane Rochoy { 9787f8d2ed0SStéphane Rochoy uint8_t bit; 9797f8d2ed0SStéphane Rochoy uint8_t group; 9807f8d2ed0SStéphane Rochoy uint8_t val; 9817f8d2ed0SStéphane Rochoy bool b; 9827f8d2ed0SStéphane Rochoy 9837f8d2ed0SStéphane Rochoy KASSERT(NCT_PIN_IS_VALID(sc, pin_num), ("%s: invalid pin number %d", 9847f8d2ed0SStéphane Rochoy __func__, pin_num)); 9857f8d2ed0SStéphane Rochoy 9867f8d2ed0SStéphane Rochoy group = NCT_PIN_GRPNUM(sc, pin_num); 9877f8d2ed0SStéphane Rochoy bit = NCT_PIN_BIT(sc, pin_num); 9887f8d2ed0SStéphane Rochoy val = nct_read_reg(sc, reg, group); 9897f8d2ed0SStéphane Rochoy b = GET_BIT(val, bit); 9907f8d2ed0SStéphane Rochoy 9917f8d2ed0SStéphane Rochoy if (__predict_false(bootverbose)) { 9927f8d2ed0SStéphane Rochoy if (nct_pin_is_input(sc, pin_num)) 9937f8d2ed0SStéphane Rochoy NCT_VERBOSE_PRINTF(sc->dev, "read %d from input pin %u<GPIO%u%u>\n", 9947f8d2ed0SStéphane Rochoy b, pin_num, group, bit); 9957f8d2ed0SStéphane Rochoy else 9967f8d2ed0SStéphane Rochoy NCT_VERBOSE_PRINTF(sc->dev, 9977f8d2ed0SStéphane Rochoy "read %d from output pin %u<GPIO%u%u>, cache miss\n", 9987f8d2ed0SStéphane Rochoy b, pin_num, group, bit); 9997f8d2ed0SStéphane Rochoy } 10007f8d2ed0SStéphane Rochoy 10017f8d2ed0SStéphane Rochoy return (b); 10027f8d2ed0SStéphane Rochoy } 10037f8d2ed0SStéphane Rochoy 1004155514eaSAndriy Gapon /* 1005155514eaSAndriy Gapon * NB: state of an input pin cannot be cached, of course. 1006155514eaSAndriy Gapon * For an output we can either take the value from the cache if it's valid 1007155514eaSAndriy Gapon * or read the state from the hadrware and cache it. 1008155514eaSAndriy Gapon */ 1009155514eaSAndriy Gapon static bool 1010155514eaSAndriy Gapon nct_read_pin(struct nct_softc *sc, uint32_t pin_num) 1011155514eaSAndriy Gapon { 1012155514eaSAndriy Gapon uint8_t bit; 1013155514eaSAndriy Gapon uint8_t group; 1014155514eaSAndriy Gapon bool val; 1015155514eaSAndriy Gapon 10167f8d2ed0SStéphane Rochoy if (nct_pin_is_input(sc, pin_num)) { 1017155514eaSAndriy Gapon return (nct_get_pin_reg(sc, REG_DAT, pin_num)); 10187f8d2ed0SStéphane Rochoy } 1019155514eaSAndriy Gapon 10207f8d2ed0SStéphane Rochoy group = NCT_PIN_GRPNUM(sc, pin_num); 10217f8d2ed0SStéphane Rochoy bit = NCT_PIN_BIT(sc, pin_num); 10227f8d2ed0SStéphane Rochoy 10237f8d2ed0SStéphane Rochoy if (GET_BIT(sc->cache.out_known[group], bit)) { 10247f8d2ed0SStéphane Rochoy val = GET_BIT(sc->cache.out[group], bit); 10257f8d2ed0SStéphane Rochoy 10267f8d2ed0SStéphane Rochoy NCT_VERBOSE_PRINTF(sc->dev, 10277f8d2ed0SStéphane Rochoy "read %d from output pin %u<GPIO%u%u>, cache hit\n", 10287f8d2ed0SStéphane Rochoy val, pin_num, group, bit); 10297f8d2ed0SStéphane Rochoy 10307f8d2ed0SStéphane Rochoy return (val); 10317f8d2ed0SStéphane Rochoy } 1032155514eaSAndriy Gapon 1033155514eaSAndriy Gapon val = nct_get_pin_reg(sc, REG_DAT, pin_num); 1034155514eaSAndriy Gapon sc->cache.out_known[group] |= 1 << bit; 1035155514eaSAndriy Gapon if (val) 1036155514eaSAndriy Gapon sc->cache.out[group] |= 1 << bit; 1037155514eaSAndriy Gapon else 1038155514eaSAndriy Gapon sc->cache.out[group] &= ~(1 << bit); 1039155514eaSAndriy Gapon return (val); 1040155514eaSAndriy Gapon } 1041155514eaSAndriy Gapon 10428e6ea10cSStéphane Rochoy /* FIXME Incorret for NCT5585D and probably other chips. */ 1043155514eaSAndriy Gapon static uint8_t 10447f8d2ed0SStéphane Rochoy nct_ppod_reg(struct nct_softc *sc, uint32_t pin_num) 1045155514eaSAndriy Gapon { 10467f8d2ed0SStéphane Rochoy uint8_t group = NCT_PIN_GRPNUM(sc, pin_num); 10477f8d2ed0SStéphane Rochoy 10487f8d2ed0SStéphane Rochoy return (sc->grpmap[group]->ppod_reg); 1049155514eaSAndriy Gapon } 1050155514eaSAndriy Gapon 1051155514eaSAndriy Gapon /* 1052155514eaSAndriy Gapon * NB: PP/OD can be configured only via configuration registers. 1053155514eaSAndriy Gapon * Also, the registers are in a different logical device. 1054155514eaSAndriy Gapon * So, this is a special case. No caching too. 1055155514eaSAndriy Gapon */ 10566b7b2d80SAdrian Chadd static void 10576b7b2d80SAdrian Chadd nct_set_pin_opendrain(struct nct_softc *sc, uint32_t pin_num) 10586b7b2d80SAdrian Chadd { 10596b7b2d80SAdrian Chadd uint8_t reg; 10606b7b2d80SAdrian Chadd uint8_t outcfg; 10616b7b2d80SAdrian Chadd 10627f8d2ed0SStéphane Rochoy reg = nct_ppod_reg(sc, pin_num); 10637f8d2ed0SStéphane Rochoy outcfg = superio_ldn_read(sc->dev, NCT_PPOD_LDN, reg); 10647f8d2ed0SStéphane Rochoy outcfg |= NCT_PIN_BITMASK(pin_num); 10657f8d2ed0SStéphane Rochoy superio_ldn_write(sc->dev, 0xf, reg, outcfg); 10666b7b2d80SAdrian Chadd } 10676b7b2d80SAdrian Chadd 10686b7b2d80SAdrian Chadd static void 10696b7b2d80SAdrian Chadd nct_set_pin_pushpull(struct nct_softc *sc, uint32_t pin_num) 10706b7b2d80SAdrian Chadd { 10716b7b2d80SAdrian Chadd uint8_t reg; 10726b7b2d80SAdrian Chadd uint8_t outcfg; 10736b7b2d80SAdrian Chadd 10747f8d2ed0SStéphane Rochoy reg = nct_ppod_reg(sc, pin_num); 10757f8d2ed0SStéphane Rochoy outcfg = superio_ldn_read(sc->dev, NCT_PPOD_LDN, reg); 10767f8d2ed0SStéphane Rochoy outcfg &= ~NCT_PIN_BITMASK(pin_num); 10777f8d2ed0SStéphane Rochoy superio_ldn_write(sc->dev, 0xf, reg, outcfg); 10786b7b2d80SAdrian Chadd } 10796b7b2d80SAdrian Chadd 10806b7b2d80SAdrian Chadd static bool 10816b7b2d80SAdrian Chadd nct_pin_is_opendrain(struct nct_softc *sc, uint32_t pin_num) 10826b7b2d80SAdrian Chadd { 10836b7b2d80SAdrian Chadd uint8_t reg; 10846b7b2d80SAdrian Chadd uint8_t outcfg; 10856b7b2d80SAdrian Chadd 10867f8d2ed0SStéphane Rochoy reg = nct_ppod_reg(sc, pin_num); 10877f8d2ed0SStéphane Rochoy outcfg = superio_ldn_read(sc->dev, NCT_PPOD_LDN, reg); 10887f8d2ed0SStéphane Rochoy return (outcfg & NCT_PIN_BITMASK(pin_num)); 10897f8d2ed0SStéphane Rochoy } 10907f8d2ed0SStéphane Rochoy 10917f8d2ed0SStéphane Rochoy static struct nct_device * 10927f8d2ed0SStéphane Rochoy nct_lookup_device(device_t dev) 10937f8d2ed0SStéphane Rochoy { 10947f8d2ed0SStéphane Rochoy struct nct_device *nctdevp; 10957f8d2ed0SStéphane Rochoy uint16_t devid; 10967f8d2ed0SStéphane Rochoy int i, extid; 10977f8d2ed0SStéphane Rochoy 10987f8d2ed0SStéphane Rochoy devid = superio_devid(dev); 10997f8d2ed0SStéphane Rochoy extid = superio_extid(dev); 11007f8d2ed0SStéphane Rochoy for (i = 0, nctdevp = nct_devices; i < nitems(nct_devices); i++, nctdevp++) { 11017f8d2ed0SStéphane Rochoy if (devid == nctdevp->devid && nctdevp->extid == extid) 11027f8d2ed0SStéphane Rochoy return (nctdevp); 11037f8d2ed0SStéphane Rochoy } 11047f8d2ed0SStéphane Rochoy return (NULL); 11056b7b2d80SAdrian Chadd } 11066b7b2d80SAdrian Chadd 11076b7b2d80SAdrian Chadd static int 11086b7b2d80SAdrian Chadd nct_probe(device_t dev) 11096b7b2d80SAdrian Chadd { 11107f8d2ed0SStéphane Rochoy struct nct_device *nctdevp; 11117f8d2ed0SStéphane Rochoy uint8_t ldn; 11126b7b2d80SAdrian Chadd 11137f8d2ed0SStéphane Rochoy ldn = superio_get_ldn(dev); 11146b7b2d80SAdrian Chadd 11157f8d2ed0SStéphane Rochoy if (superio_vendor(dev) != SUPERIO_VENDOR_NUVOTON) { 11167f8d2ed0SStéphane Rochoy NCT_VERBOSE_PRINTF(dev, "ldn 0x%x not a Nuvoton device\n", ldn); 1117e3df342aSAndriy Gapon return (ENXIO); 11187f8d2ed0SStéphane Rochoy } 11197f8d2ed0SStéphane Rochoy if (superio_get_type(dev) != SUPERIO_DEV_GPIO) { 11207f8d2ed0SStéphane Rochoy NCT_VERBOSE_PRINTF(dev, "ldn 0x%x not a GPIO device\n", ldn); 11217f8d2ed0SStéphane Rochoy return (ENXIO); 11227f8d2ed0SStéphane Rochoy } 11236b7b2d80SAdrian Chadd 11247f8d2ed0SStéphane Rochoy nctdevp = nct_lookup_device(dev); 11257f8d2ed0SStéphane Rochoy if (nctdevp == NULL) { 11267f8d2ed0SStéphane Rochoy NCT_VERBOSE_PRINTF(dev, "ldn 0x%x not supported\n", ldn); 11277f8d2ed0SStéphane Rochoy return (ENXIO); 11287f8d2ed0SStéphane Rochoy } 11297f8d2ed0SStéphane Rochoy device_set_desc(dev, nctdevp->descr); 11306b7b2d80SAdrian Chadd return (BUS_PROBE_DEFAULT); 11316b7b2d80SAdrian Chadd } 11326b7b2d80SAdrian Chadd 11336b7b2d80SAdrian Chadd static int 11346b7b2d80SAdrian Chadd nct_attach(device_t dev) 11356b7b2d80SAdrian Chadd { 11366b7b2d80SAdrian Chadd struct nct_softc *sc; 11377f8d2ed0SStéphane Rochoy struct nct_gpio_group *gp; 11387f8d2ed0SStéphane Rochoy uint32_t pin_num; 11397f8d2ed0SStéphane Rochoy uint8_t v; 11407f8d2ed0SStéphane Rochoy int flags, i, g; 11416b7b2d80SAdrian Chadd 11426b7b2d80SAdrian Chadd sc = device_get_softc(dev); 1143e3df342aSAndriy Gapon sc->dev = dev; 11447f8d2ed0SStéphane Rochoy sc->nctdevp = nct_lookup_device(dev); 11457f8d2ed0SStéphane Rochoy 11467f8d2ed0SStéphane Rochoy flags = 0; 11477f8d2ed0SStéphane Rochoy (void)resource_int_value(device_get_name(dev), device_get_unit(dev), "flags", &flags); 11487f8d2ed0SStéphane Rochoy 11497f8d2ed0SStéphane Rochoy if ((flags & NCT_PREFER_INDIRECT_CHANNEL) == 0) { 11507f8d2ed0SStéphane Rochoy uint16_t iobase; 11517f8d2ed0SStéphane Rochoy device_t dev_8; 11526b7b2d80SAdrian Chadd 1153155514eaSAndriy Gapon /* 1154155514eaSAndriy Gapon * As strange as it may seem, I/O port base is configured in the 1155155514eaSAndriy Gapon * Logical Device 8 which is primarily used for WDT, but also plays 1156155514eaSAndriy Gapon * a role in GPIO configuration. 1157155514eaSAndriy Gapon */ 1158155514eaSAndriy Gapon iobase = 0; 1159155514eaSAndriy Gapon dev_8 = superio_find_dev(device_get_parent(dev), SUPERIO_DEV_WDT, 8); 1160155514eaSAndriy Gapon if (dev_8 != NULL) 1161155514eaSAndriy Gapon iobase = superio_get_iobase(dev_8); 1162155514eaSAndriy Gapon if (iobase != 0 && iobase != 0xffff) { 11637f8d2ed0SStéphane Rochoy int err; 11647f8d2ed0SStéphane Rochoy 11657f8d2ed0SStéphane Rochoy NCT_VERBOSE_PRINTF(dev, "iobase %#x\n", iobase); 1166155514eaSAndriy Gapon sc->curgrp = -1; 1167155514eaSAndriy Gapon sc->iorid = 0; 1168155514eaSAndriy Gapon err = bus_set_resource(dev, SYS_RES_IOPORT, sc->iorid, 11698e6ea10cSStéphane Rochoy iobase, 7); /* FIXME NCT6796D-E have 8 registers according to table 18.3. */ 1170155514eaSAndriy Gapon if (err == 0) { 1171155514eaSAndriy Gapon sc->iores = bus_alloc_resource_any(dev, SYS_RES_IOPORT, 1172155514eaSAndriy Gapon &sc->iorid, RF_ACTIVE); 1173155514eaSAndriy Gapon if (sc->iores == NULL) { 1174155514eaSAndriy Gapon device_printf(dev, "can't map i/o space, " 11757f8d2ed0SStéphane Rochoy "iobase=%#x\n", iobase); 1176155514eaSAndriy Gapon } 1177155514eaSAndriy Gapon } else { 1178155514eaSAndriy Gapon device_printf(dev, 11797f8d2ed0SStéphane Rochoy "failed to set io port resource at %#x\n", iobase); 1180155514eaSAndriy Gapon } 1181155514eaSAndriy Gapon } 11827f8d2ed0SStéphane Rochoy } 11837f8d2ed0SStéphane Rochoy NCT_VERBOSE_PRINTF(dev, "iores %p %s channel\n", 11847f8d2ed0SStéphane Rochoy sc->iores, (sc->iores ? "direct" : "indirect")); 1185155514eaSAndriy Gapon 11867f8d2ed0SStéphane Rochoy /* Enable GPIO groups */ 11877f8d2ed0SStéphane Rochoy for (g = 0, gp = sc->nctdevp->groups; g < sc->nctdevp->ngroups; g++, gp++) { 11887f8d2ed0SStéphane Rochoy NCT_VERBOSE_PRINTF(dev, 11897f8d2ed0SStéphane Rochoy "GPIO%d: %d pins, enable with mask 0x%x via ldn 0x%x reg 0x%x\n", 11907f8d2ed0SStéphane Rochoy gp->grpnum, gp->npins, gp->enable_mask, gp->enable_ldn, 11917f8d2ed0SStéphane Rochoy gp->enable_reg); 11927f8d2ed0SStéphane Rochoy v = superio_ldn_read(dev, gp->enable_ldn, gp->enable_reg); 11937f8d2ed0SStéphane Rochoy v |= gp->enable_mask; 11947f8d2ed0SStéphane Rochoy superio_ldn_write(dev, gp->enable_ldn, gp->enable_reg, v); 11957f8d2ed0SStéphane Rochoy } 1196e3df342aSAndriy Gapon 1197e3df342aSAndriy Gapon GPIO_LOCK_INIT(sc); 1198e3df342aSAndriy Gapon GPIO_LOCK(sc); 11996b7b2d80SAdrian Chadd 12007f8d2ed0SStéphane Rochoy pin_num = 0; 12017f8d2ed0SStéphane Rochoy sc->npins = 0; 12027f8d2ed0SStéphane Rochoy for (g = 0, gp = sc->nctdevp->groups; g < sc->nctdevp->ngroups; g++, gp++) { 1203f03a7e52SStéphane Rochoy 1204f03a7e52SStéphane Rochoy sc->grpmap[gp->grpnum] = gp; 1205f03a7e52SStéphane Rochoy 1206f03a7e52SStéphane Rochoy /* 1207f03a7e52SStéphane Rochoy * Caching input values is meaningless as an input can be changed at any 1208f03a7e52SStéphane Rochoy * time by an external agent. But outputs are controlled by this 1209f03a7e52SStéphane Rochoy * driver, so it can cache their state. Also, the hardware remembers 1210f03a7e52SStéphane Rochoy * the output state of a pin when the pin is switched to input mode and 1211f03a7e52SStéphane Rochoy * then back to output mode. So, the cache stays valid. 1212f03a7e52SStéphane Rochoy * The only problem is with pins that are in input mode at the attach 1213f03a7e52SStéphane Rochoy * time. For them the output state is not known until it is set by the 1214f03a7e52SStéphane Rochoy * driver for the first time. 1215f03a7e52SStéphane Rochoy * 'out' and 'out_known' bits form a tri-state output cache: 1216f03a7e52SStéphane Rochoy * |-----+-----------+---------| 1217f03a7e52SStéphane Rochoy * | out | out_known | cache | 1218f03a7e52SStéphane Rochoy * |-----+-----------+---------| 1219f03a7e52SStéphane Rochoy * | X | 0 | invalid | 1220f03a7e52SStéphane Rochoy * | 0 | 1 | 0 | 1221f03a7e52SStéphane Rochoy * | 1 | 1 | 1 | 1222f03a7e52SStéphane Rochoy * |-----+-----------+---------| 1223f03a7e52SStéphane Rochoy */ 1224f03a7e52SStéphane Rochoy sc->cache.inv[gp->grpnum] = nct_read_reg(sc, REG_INV, gp->grpnum); 1225f03a7e52SStéphane Rochoy sc->cache.ior[gp->grpnum] = nct_read_reg(sc, REG_IOR, gp->grpnum); 1226f03a7e52SStéphane Rochoy sc->cache.out[gp->grpnum] = nct_read_reg(sc, REG_DAT, gp->grpnum); 1227f03a7e52SStéphane Rochoy sc->cache.out_known[gp->grpnum] = ~sc->cache.ior[gp->grpnum]; 1228f03a7e52SStéphane Rochoy 12297f8d2ed0SStéphane Rochoy sc->npins += gp->npins; 12307f8d2ed0SStéphane Rochoy for (i = 0; i < gp->npins; i++, pin_num++) { 12317f8d2ed0SStéphane Rochoy struct gpio_pin *pin; 12327f8d2ed0SStéphane Rochoy 12337f8d2ed0SStéphane Rochoy sc->pinmap[pin_num].group = gp; 12347f8d2ed0SStéphane Rochoy sc->pinmap[pin_num].grpnum = gp->grpnum; 12357f8d2ed0SStéphane Rochoy sc->pinmap[pin_num].bit = gp->pinbits[i]; 12367f8d2ed0SStéphane Rochoy 12377f8d2ed0SStéphane Rochoy pin = &sc->pins[pin_num]; 12387f8d2ed0SStéphane Rochoy pin->gp_pin = pin_num; 12397f8d2ed0SStéphane Rochoy pin->gp_caps = gp->caps; 12407f8d2ed0SStéphane Rochoy pin->gp_flags = 0; 12417f8d2ed0SStéphane Rochoy 12427f8d2ed0SStéphane Rochoy snprintf(pin->gp_name, GPIOMAXNAME, "GPIO%u%u", 12437f8d2ed0SStéphane Rochoy gp->grpnum, gp->pinbits[i]); 12447f8d2ed0SStéphane Rochoy 12457f8d2ed0SStéphane Rochoy if (nct_pin_is_input(sc, pin_num)) 12467f8d2ed0SStéphane Rochoy pin->gp_flags |= GPIO_PIN_INPUT; 12477f8d2ed0SStéphane Rochoy else 12487f8d2ed0SStéphane Rochoy pin->gp_flags |= GPIO_PIN_OUTPUT; 12497f8d2ed0SStéphane Rochoy 12507f8d2ed0SStéphane Rochoy if (nct_pin_is_opendrain(sc, pin_num)) 12517f8d2ed0SStéphane Rochoy pin->gp_flags |= GPIO_PIN_OPENDRAIN; 12527f8d2ed0SStéphane Rochoy else 12537f8d2ed0SStéphane Rochoy pin->gp_flags |= GPIO_PIN_PUSHPULL; 12547f8d2ed0SStéphane Rochoy 12557f8d2ed0SStéphane Rochoy if (nct_pin_is_inverted(sc, pin_num)) 12567f8d2ed0SStéphane Rochoy pin->gp_flags |= (GPIO_PIN_INVIN | GPIO_PIN_INVOUT); 12577f8d2ed0SStéphane Rochoy } 12587f8d2ed0SStéphane Rochoy } 12597f8d2ed0SStéphane Rochoy NCT_VERBOSE_PRINTF(dev, "%d pins available\n", sc->npins); 1260155514eaSAndriy Gapon 12616b7b2d80SAdrian Chadd GPIO_UNLOCK(sc); 12626b7b2d80SAdrian Chadd 12636b7b2d80SAdrian Chadd sc->busdev = gpiobus_attach_bus(dev); 12646b7b2d80SAdrian Chadd if (sc->busdev == NULL) { 12657f8d2ed0SStéphane Rochoy device_printf(dev, "failed to attach to gpiobus\n"); 12666b7b2d80SAdrian Chadd GPIO_LOCK_DESTROY(sc); 12676b7b2d80SAdrian Chadd return (ENXIO); 12686b7b2d80SAdrian Chadd } 12696b7b2d80SAdrian Chadd 12706b7b2d80SAdrian Chadd return (0); 12716b7b2d80SAdrian Chadd } 12726b7b2d80SAdrian Chadd 12736b7b2d80SAdrian Chadd static int 12746b7b2d80SAdrian Chadd nct_detach(device_t dev) 12756b7b2d80SAdrian Chadd { 12766b7b2d80SAdrian Chadd struct nct_softc *sc; 12776b7b2d80SAdrian Chadd 12786b7b2d80SAdrian Chadd sc = device_get_softc(dev); 12796b7b2d80SAdrian Chadd gpiobus_detach_bus(dev); 12806b7b2d80SAdrian Chadd 1281155514eaSAndriy Gapon if (sc->iores != NULL) 1282155514eaSAndriy Gapon bus_release_resource(dev, SYS_RES_IOPORT, sc->iorid, sc->iores); 12836b7b2d80SAdrian Chadd GPIO_ASSERT_UNLOCKED(sc); 12846b7b2d80SAdrian Chadd GPIO_LOCK_DESTROY(sc); 12856b7b2d80SAdrian Chadd 12866b7b2d80SAdrian Chadd return (0); 12876b7b2d80SAdrian Chadd } 12886b7b2d80SAdrian Chadd 12896b7b2d80SAdrian Chadd static device_t 12906b7b2d80SAdrian Chadd nct_gpio_get_bus(device_t dev) 12916b7b2d80SAdrian Chadd { 12926b7b2d80SAdrian Chadd struct nct_softc *sc; 12936b7b2d80SAdrian Chadd 12946b7b2d80SAdrian Chadd sc = device_get_softc(dev); 12956b7b2d80SAdrian Chadd 12966b7b2d80SAdrian Chadd return (sc->busdev); 12976b7b2d80SAdrian Chadd } 12986b7b2d80SAdrian Chadd 12996b7b2d80SAdrian Chadd static int 13007f8d2ed0SStéphane Rochoy nct_gpio_pin_max(device_t dev, int *maxpin) 13016b7b2d80SAdrian Chadd { 13027f8d2ed0SStéphane Rochoy struct nct_softc *sc; 13036b7b2d80SAdrian Chadd 13047f8d2ed0SStéphane Rochoy sc = device_get_softc(dev); 13057f8d2ed0SStéphane Rochoy *maxpin = sc->npins - 1; 13066b7b2d80SAdrian Chadd return (0); 13076b7b2d80SAdrian Chadd } 13086b7b2d80SAdrian Chadd 13096b7b2d80SAdrian Chadd static int 13106b7b2d80SAdrian Chadd nct_gpio_pin_set(device_t dev, uint32_t pin_num, uint32_t pin_value) 13116b7b2d80SAdrian Chadd { 13126b7b2d80SAdrian Chadd struct nct_softc *sc; 13136b7b2d80SAdrian Chadd 13147f8d2ed0SStéphane Rochoy sc = device_get_softc(dev); 13157f8d2ed0SStéphane Rochoy 13167f8d2ed0SStéphane Rochoy if (!NCT_PIN_IS_VALID(sc, pin_num)) 13176b7b2d80SAdrian Chadd return (EINVAL); 13186b7b2d80SAdrian Chadd 13196b7b2d80SAdrian Chadd GPIO_LOCK(sc); 1320155514eaSAndriy Gapon if ((sc->pins[pin_num].gp_flags & GPIO_PIN_OUTPUT) == 0) { 1321155514eaSAndriy Gapon GPIO_UNLOCK(sc); 1322155514eaSAndriy Gapon return (EINVAL); 1323155514eaSAndriy Gapon } 13246b7b2d80SAdrian Chadd nct_write_pin(sc, pin_num, pin_value); 13256b7b2d80SAdrian Chadd GPIO_UNLOCK(sc); 13266b7b2d80SAdrian Chadd 13276b7b2d80SAdrian Chadd return (0); 13286b7b2d80SAdrian Chadd } 13296b7b2d80SAdrian Chadd 13306b7b2d80SAdrian Chadd static int 13316b7b2d80SAdrian Chadd nct_gpio_pin_get(device_t dev, uint32_t pin_num, uint32_t *pin_value) 13326b7b2d80SAdrian Chadd { 13336b7b2d80SAdrian Chadd struct nct_softc *sc; 13346b7b2d80SAdrian Chadd 13357f8d2ed0SStéphane Rochoy sc = device_get_softc(dev); 13367f8d2ed0SStéphane Rochoy 13377f8d2ed0SStéphane Rochoy if (!NCT_PIN_IS_VALID(sc, pin_num)) 13386b7b2d80SAdrian Chadd return (EINVAL); 13396b7b2d80SAdrian Chadd 13406b7b2d80SAdrian Chadd GPIO_ASSERT_UNLOCKED(sc); 13416b7b2d80SAdrian Chadd GPIO_LOCK(sc); 13426b7b2d80SAdrian Chadd *pin_value = nct_read_pin(sc, pin_num); 13436b7b2d80SAdrian Chadd GPIO_UNLOCK(sc); 13446b7b2d80SAdrian Chadd 13456b7b2d80SAdrian Chadd return (0); 13466b7b2d80SAdrian Chadd } 13476b7b2d80SAdrian Chadd 13486b7b2d80SAdrian Chadd static int 13496b7b2d80SAdrian Chadd nct_gpio_pin_toggle(device_t dev, uint32_t pin_num) 13506b7b2d80SAdrian Chadd { 13516b7b2d80SAdrian Chadd struct nct_softc *sc; 13526b7b2d80SAdrian Chadd 13537f8d2ed0SStéphane Rochoy sc = device_get_softc(dev); 13547f8d2ed0SStéphane Rochoy 13557f8d2ed0SStéphane Rochoy if (!NCT_PIN_IS_VALID(sc, pin_num)) 13566b7b2d80SAdrian Chadd return (EINVAL); 13576b7b2d80SAdrian Chadd 13586b7b2d80SAdrian Chadd GPIO_ASSERT_UNLOCKED(sc); 13596b7b2d80SAdrian Chadd GPIO_LOCK(sc); 1360155514eaSAndriy Gapon if ((sc->pins[pin_num].gp_flags & GPIO_PIN_OUTPUT) == 0) { 1361155514eaSAndriy Gapon GPIO_UNLOCK(sc); 1362155514eaSAndriy Gapon return (EINVAL); 1363155514eaSAndriy Gapon } 13646b7b2d80SAdrian Chadd if (nct_read_pin(sc, pin_num)) 13656b7b2d80SAdrian Chadd nct_write_pin(sc, pin_num, 0); 13666b7b2d80SAdrian Chadd else 13676b7b2d80SAdrian Chadd nct_write_pin(sc, pin_num, 1); 13686b7b2d80SAdrian Chadd 13696b7b2d80SAdrian Chadd GPIO_UNLOCK(sc); 13706b7b2d80SAdrian Chadd 13716b7b2d80SAdrian Chadd return (0); 13726b7b2d80SAdrian Chadd } 13736b7b2d80SAdrian Chadd 13746b7b2d80SAdrian Chadd static int 13756b7b2d80SAdrian Chadd nct_gpio_pin_getcaps(device_t dev, uint32_t pin_num, uint32_t *caps) 13766b7b2d80SAdrian Chadd { 13776b7b2d80SAdrian Chadd struct nct_softc *sc; 13786b7b2d80SAdrian Chadd 13797f8d2ed0SStéphane Rochoy sc = device_get_softc(dev); 13807f8d2ed0SStéphane Rochoy 13817f8d2ed0SStéphane Rochoy if (!NCT_PIN_IS_VALID(sc, pin_num)) 13826b7b2d80SAdrian Chadd return (EINVAL); 13836b7b2d80SAdrian Chadd 13846b7b2d80SAdrian Chadd GPIO_ASSERT_UNLOCKED(sc); 13856b7b2d80SAdrian Chadd GPIO_LOCK(sc); 13866b7b2d80SAdrian Chadd *caps = sc->pins[pin_num].gp_caps; 13876b7b2d80SAdrian Chadd GPIO_UNLOCK(sc); 13886b7b2d80SAdrian Chadd 13896b7b2d80SAdrian Chadd return (0); 13906b7b2d80SAdrian Chadd } 13916b7b2d80SAdrian Chadd 13926b7b2d80SAdrian Chadd static int 13936b7b2d80SAdrian Chadd nct_gpio_pin_getflags(device_t dev, uint32_t pin_num, uint32_t *flags) 13946b7b2d80SAdrian Chadd { 13956b7b2d80SAdrian Chadd struct nct_softc *sc; 13966b7b2d80SAdrian Chadd 13977f8d2ed0SStéphane Rochoy sc = device_get_softc(dev); 13987f8d2ed0SStéphane Rochoy 13997f8d2ed0SStéphane Rochoy if (!NCT_PIN_IS_VALID(sc, pin_num)) 14006b7b2d80SAdrian Chadd return (EINVAL); 14016b7b2d80SAdrian Chadd 14026b7b2d80SAdrian Chadd GPIO_ASSERT_UNLOCKED(sc); 14036b7b2d80SAdrian Chadd GPIO_LOCK(sc); 14046b7b2d80SAdrian Chadd *flags = sc->pins[pin_num].gp_flags; 14056b7b2d80SAdrian Chadd GPIO_UNLOCK(sc); 14066b7b2d80SAdrian Chadd 14076b7b2d80SAdrian Chadd return (0); 14086b7b2d80SAdrian Chadd } 14096b7b2d80SAdrian Chadd 14106b7b2d80SAdrian Chadd static int 14116b7b2d80SAdrian Chadd nct_gpio_pin_getname(device_t dev, uint32_t pin_num, char *name) 14126b7b2d80SAdrian Chadd { 14136b7b2d80SAdrian Chadd struct nct_softc *sc; 14146b7b2d80SAdrian Chadd 14157f8d2ed0SStéphane Rochoy sc = device_get_softc(dev); 14167f8d2ed0SStéphane Rochoy 14177f8d2ed0SStéphane Rochoy if (!NCT_PIN_IS_VALID(sc, pin_num)) 14186b7b2d80SAdrian Chadd return (EINVAL); 14196b7b2d80SAdrian Chadd 14206b7b2d80SAdrian Chadd GPIO_ASSERT_UNLOCKED(sc); 14216b7b2d80SAdrian Chadd GPIO_LOCK(sc); 14226b7b2d80SAdrian Chadd memcpy(name, sc->pins[pin_num].gp_name, GPIOMAXNAME); 14236b7b2d80SAdrian Chadd GPIO_UNLOCK(sc); 14246b7b2d80SAdrian Chadd 14256b7b2d80SAdrian Chadd return (0); 14266b7b2d80SAdrian Chadd } 14276b7b2d80SAdrian Chadd 14286b7b2d80SAdrian Chadd static int 14296b7b2d80SAdrian Chadd nct_gpio_pin_setflags(device_t dev, uint32_t pin_num, uint32_t flags) 14306b7b2d80SAdrian Chadd { 14316b7b2d80SAdrian Chadd struct nct_softc *sc; 14326b7b2d80SAdrian Chadd struct gpio_pin *pin; 14336b7b2d80SAdrian Chadd 14347f8d2ed0SStéphane Rochoy sc = device_get_softc(dev); 14357f8d2ed0SStéphane Rochoy 14367f8d2ed0SStéphane Rochoy if (!NCT_PIN_IS_VALID(sc, pin_num)) 14376b7b2d80SAdrian Chadd return (EINVAL); 14386b7b2d80SAdrian Chadd 14396b7b2d80SAdrian Chadd pin = &sc->pins[pin_num]; 14406b7b2d80SAdrian Chadd if ((flags & pin->gp_caps) != flags) 14416b7b2d80SAdrian Chadd return (EINVAL); 14426b7b2d80SAdrian Chadd 14436b7b2d80SAdrian Chadd if ((flags & (GPIO_PIN_INPUT | GPIO_PIN_OUTPUT)) == 14446b7b2d80SAdrian Chadd (GPIO_PIN_INPUT | GPIO_PIN_OUTPUT)) { 14456b7b2d80SAdrian Chadd return (EINVAL); 14466b7b2d80SAdrian Chadd } 14476b7b2d80SAdrian Chadd if ((flags & (GPIO_PIN_OPENDRAIN | GPIO_PIN_PUSHPULL)) == 14486b7b2d80SAdrian Chadd (GPIO_PIN_OPENDRAIN | GPIO_PIN_PUSHPULL)) { 1449155514eaSAndriy Gapon return (EINVAL); 1450155514eaSAndriy Gapon } 1451155514eaSAndriy Gapon if ((flags & (GPIO_PIN_INVIN | GPIO_PIN_INVOUT)) == 1452155514eaSAndriy Gapon (GPIO_PIN_INVIN | GPIO_PIN_INVOUT)) { 14536b7b2d80SAdrian Chadd return (EINVAL); 14546b7b2d80SAdrian Chadd } 14556b7b2d80SAdrian Chadd 1456155514eaSAndriy Gapon GPIO_ASSERT_UNLOCKED(sc); 1457155514eaSAndriy Gapon GPIO_LOCK(sc); 14587f8d2ed0SStéphane Rochoy 14597f8d2ed0SStéphane Rochoy /* input or output */ 1460155514eaSAndriy Gapon if ((flags & (GPIO_PIN_INPUT | GPIO_PIN_OUTPUT)) != 0) { 1461155514eaSAndriy Gapon nct_set_pin_input(sc, pin_num, (flags & GPIO_PIN_INPUT) != 0); 1462155514eaSAndriy Gapon pin->gp_flags &= ~(GPIO_PIN_INPUT | GPIO_PIN_OUTPUT); 1463155514eaSAndriy Gapon pin->gp_flags |= flags & (GPIO_PIN_INPUT | GPIO_PIN_OUTPUT); 1464155514eaSAndriy Gapon } 14657f8d2ed0SStéphane Rochoy 14667f8d2ed0SStéphane Rochoy /* invert */ 1467155514eaSAndriy Gapon if ((flags & (GPIO_PIN_INVIN | GPIO_PIN_INVOUT)) != 0) { 14687f8d2ed0SStéphane Rochoy nct_set_pin_inverted(sc, pin_num, 1); 14697f8d2ed0SStéphane Rochoy pin->gp_flags |= (GPIO_PIN_INVIN | GPIO_PIN_INVOUT); 14707f8d2ed0SStéphane Rochoy } else { 14717f8d2ed0SStéphane Rochoy nct_set_pin_inverted(sc, pin_num, 0); 1472155514eaSAndriy Gapon pin->gp_flags &= ~(GPIO_PIN_INVIN | GPIO_PIN_INVOUT); 1473155514eaSAndriy Gapon } 14747f8d2ed0SStéphane Rochoy 14757f8d2ed0SStéphane Rochoy /* Open drain or push pull */ 1476155514eaSAndriy Gapon if ((flags & (GPIO_PIN_OPENDRAIN | GPIO_PIN_PUSHPULL)) != 0) { 14776b7b2d80SAdrian Chadd if (flags & GPIO_PIN_OPENDRAIN) 14786b7b2d80SAdrian Chadd nct_set_pin_opendrain(sc, pin_num); 14796b7b2d80SAdrian Chadd else 14806b7b2d80SAdrian Chadd nct_set_pin_pushpull(sc, pin_num); 1481155514eaSAndriy Gapon pin->gp_flags &= ~(GPIO_PIN_OPENDRAIN | GPIO_PIN_PUSHPULL); 1482155514eaSAndriy Gapon pin->gp_flags |= 1483155514eaSAndriy Gapon flags & (GPIO_PIN_OPENDRAIN | GPIO_PIN_PUSHPULL); 14846b7b2d80SAdrian Chadd } 14856b7b2d80SAdrian Chadd GPIO_UNLOCK(sc); 14866b7b2d80SAdrian Chadd 14876b7b2d80SAdrian Chadd return (0); 14886b7b2d80SAdrian Chadd } 14896b7b2d80SAdrian Chadd 14906b7b2d80SAdrian Chadd static device_method_t nct_methods[] = { 14916b7b2d80SAdrian Chadd /* Device interface */ 14926b7b2d80SAdrian Chadd DEVMETHOD(device_probe, nct_probe), 14936b7b2d80SAdrian Chadd DEVMETHOD(device_attach, nct_attach), 14946b7b2d80SAdrian Chadd DEVMETHOD(device_detach, nct_detach), 14956b7b2d80SAdrian Chadd 14966b7b2d80SAdrian Chadd /* GPIO */ 14976b7b2d80SAdrian Chadd DEVMETHOD(gpio_get_bus, nct_gpio_get_bus), 14986b7b2d80SAdrian Chadd DEVMETHOD(gpio_pin_max, nct_gpio_pin_max), 14996b7b2d80SAdrian Chadd DEVMETHOD(gpio_pin_get, nct_gpio_pin_get), 15006b7b2d80SAdrian Chadd DEVMETHOD(gpio_pin_set, nct_gpio_pin_set), 15016b7b2d80SAdrian Chadd DEVMETHOD(gpio_pin_toggle, nct_gpio_pin_toggle), 15026b7b2d80SAdrian Chadd DEVMETHOD(gpio_pin_getname, nct_gpio_pin_getname), 15036b7b2d80SAdrian Chadd DEVMETHOD(gpio_pin_getcaps, nct_gpio_pin_getcaps), 15046b7b2d80SAdrian Chadd DEVMETHOD(gpio_pin_getflags, nct_gpio_pin_getflags), 15056b7b2d80SAdrian Chadd DEVMETHOD(gpio_pin_setflags, nct_gpio_pin_setflags), 15066b7b2d80SAdrian Chadd 15076b7b2d80SAdrian Chadd DEVMETHOD_END 15086b7b2d80SAdrian Chadd }; 15096b7b2d80SAdrian Chadd 1510e3df342aSAndriy Gapon static driver_t nct_driver = { 15116b7b2d80SAdrian Chadd "gpio", 15126b7b2d80SAdrian Chadd nct_methods, 15136b7b2d80SAdrian Chadd sizeof(struct nct_softc) 15146b7b2d80SAdrian Chadd }; 15156b7b2d80SAdrian Chadd 151684c5f982SJohn Baldwin DRIVER_MODULE(nctgpio, superio, nct_driver, NULL, NULL); 15176b7b2d80SAdrian Chadd MODULE_DEPEND(nctgpio, gpiobus, 1, 1, 1); 1518e3df342aSAndriy Gapon MODULE_DEPEND(nctgpio, superio, 1, 1, 1); 1519e3df342aSAndriy Gapon MODULE_VERSION(nctgpio, 1); 1520