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 { 154*8e6ea10cSStéphane Rochoy .devid = 0xa025, 155*8e6ea10cSStéphane Rochoy .descr = "GPIO on Winbond 83627DHG IC ver. 5", 156*8e6ea10cSStéphane Rochoy .ngroups = 5, 157*8e6ea10cSStéphane Rochoy .groups = { 158*8e6ea10cSStéphane Rochoy { 159*8e6ea10cSStéphane Rochoy .grpnum = 2, 160*8e6ea10cSStéphane Rochoy .pinbits = { 0, 1, 2, 3, 4, 5, 6, 7 }, 161*8e6ea10cSStéphane Rochoy .enable_ldn = 0x09, 162*8e6ea10cSStéphane Rochoy .enable_reg = 0x30, 163*8e6ea10cSStéphane Rochoy .enable_mask = 0x01, 164*8e6ea10cSStéphane Rochoy .data_ldn = 0x09, 165*8e6ea10cSStéphane Rochoy .ppod_reg = 0xe0, /* FIXME Need to check for this group. */ 166*8e6ea10cSStéphane Rochoy .caps = NCT_GPIO_CAPS, 167*8e6ea10cSStéphane Rochoy .npins = 8, 168*8e6ea10cSStéphane Rochoy .iobase = 0xe3, 169*8e6ea10cSStéphane Rochoy }, 170*8e6ea10cSStéphane Rochoy { 171*8e6ea10cSStéphane Rochoy .grpnum = 3, 172*8e6ea10cSStéphane Rochoy .pinbits = { 0, 1, 2, 3, 4, 5, 6, 7 }, 173*8e6ea10cSStéphane Rochoy .enable_ldn = 0x09, 174*8e6ea10cSStéphane Rochoy .enable_reg = 0x30, 175*8e6ea10cSStéphane Rochoy .enable_mask = 0x02, 176*8e6ea10cSStéphane Rochoy .data_ldn = 0x09, 177*8e6ea10cSStéphane Rochoy .ppod_reg = 0xe1, /* FIXME Need to check for this group. */ 178*8e6ea10cSStéphane Rochoy .caps = NCT_GPIO_CAPS, 179*8e6ea10cSStéphane Rochoy .npins = 8, 180*8e6ea10cSStéphane Rochoy .iobase = 0xf0, 181*8e6ea10cSStéphane Rochoy }, 182*8e6ea10cSStéphane Rochoy { 183*8e6ea10cSStéphane Rochoy .grpnum = 4, 184*8e6ea10cSStéphane Rochoy .pinbits = { 0, 1, 2, 3, 4, 5, 6, 7 }, 185*8e6ea10cSStéphane Rochoy .enable_ldn = 0x09, 186*8e6ea10cSStéphane Rochoy .enable_reg = 0x30, 187*8e6ea10cSStéphane Rochoy .enable_mask = 0x04, 188*8e6ea10cSStéphane Rochoy .data_ldn = 0x09, 189*8e6ea10cSStéphane Rochoy .ppod_reg = 0xe1, /* FIXME Need to check for this group. */ 190*8e6ea10cSStéphane Rochoy .caps = NCT_GPIO_CAPS, 191*8e6ea10cSStéphane Rochoy .npins = 8, 192*8e6ea10cSStéphane Rochoy .iobase = 0xf4, 193*8e6ea10cSStéphane Rochoy }, 194*8e6ea10cSStéphane Rochoy { 195*8e6ea10cSStéphane Rochoy .grpnum = 5, 196*8e6ea10cSStéphane Rochoy .pinbits = { 0, 1, 2, 3, 4, 5, 6, 7 }, 197*8e6ea10cSStéphane Rochoy .enable_ldn = 0x09, 198*8e6ea10cSStéphane Rochoy .enable_reg = 0x30, 199*8e6ea10cSStéphane Rochoy .enable_mask = 0x08, 200*8e6ea10cSStéphane Rochoy .data_ldn = 0x09, 201*8e6ea10cSStéphane Rochoy .ppod_reg = 0xe1, /* FIXME Need to check for this group. */ 202*8e6ea10cSStéphane Rochoy .caps = NCT_GPIO_CAPS, 203*8e6ea10cSStéphane Rochoy .npins = 8, 204*8e6ea10cSStéphane Rochoy .iobase = 0xe0, 205*8e6ea10cSStéphane Rochoy }, 206*8e6ea10cSStéphane Rochoy { 207*8e6ea10cSStéphane Rochoy .grpnum = 6, 208*8e6ea10cSStéphane Rochoy .pinbits = { 0, 1, 2, 3, 4, 5, 6, 7 }, 209*8e6ea10cSStéphane Rochoy .enable_ldn = 0x07, 210*8e6ea10cSStéphane Rochoy .enable_reg = 0x30, 211*8e6ea10cSStéphane Rochoy .enable_mask = 0x01, 212*8e6ea10cSStéphane Rochoy .data_ldn = 0x07, 213*8e6ea10cSStéphane Rochoy .ppod_reg = 0xe1, /* FIXME Need to check for this group. */ 214*8e6ea10cSStéphane Rochoy .caps = NCT_GPIO_CAPS, 215*8e6ea10cSStéphane Rochoy .npins = 8, 216*8e6ea10cSStéphane Rochoy .iobase = 0xf4, 217*8e6ea10cSStéphane Rochoy }, 218*8e6ea10cSStéphane Rochoy }, 219*8e6ea10cSStéphane Rochoy }, 220*8e6ea10cSSté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 { 252*8e6ea10cSSté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 }, 313*8e6ea10cSStéphane Rochoy { 314*8e6ea10cSStéphane Rochoy .devid = 0xd42a, 315*8e6ea10cSStéphane Rochoy .extid = 1, 316*8e6ea10cSStéphane Rochoy .descr = "GPIO on Nuvoton NCT6796D-E", 317*8e6ea10cSStéphane Rochoy .ngroups = 10, 318*8e6ea10cSStéphane Rochoy .groups = { 319*8e6ea10cSStéphane Rochoy { 320*8e6ea10cSStéphane Rochoy .grpnum = 0, 321*8e6ea10cSStéphane Rochoy .pinbits = { 0, 1, 2, 3, 4, 5, 6, 7 }, 322*8e6ea10cSStéphane Rochoy .enable_ldn = 0x08, 323*8e6ea10cSStéphane Rochoy .enable_reg = 0x30, 324*8e6ea10cSStéphane Rochoy .enable_mask = 0x02, 325*8e6ea10cSStéphane Rochoy .data_ldn = 0x08, 326*8e6ea10cSStéphane Rochoy .ppod_reg = 0xe0, /* FIXME Need to check for this group. */ 327*8e6ea10cSStéphane Rochoy .caps = NCT_GPIO_CAPS, 328*8e6ea10cSStéphane Rochoy .npins = 8, 329*8e6ea10cSStéphane Rochoy .iobase = 0xe0, 330*8e6ea10cSStéphane Rochoy }, 331*8e6ea10cSStéphane Rochoy { 332*8e6ea10cSStéphane Rochoy .grpnum = 1, 333*8e6ea10cSStéphane Rochoy .pinbits = { 0, 1, 2, 3, 4, 5, 6, 7 }, 334*8e6ea10cSStéphane Rochoy .enable_ldn = 0x08, 335*8e6ea10cSStéphane Rochoy .enable_reg = 0x30, 336*8e6ea10cSStéphane Rochoy .enable_mask = 0x80, 337*8e6ea10cSStéphane Rochoy .data_ldn = 0x08, 338*8e6ea10cSStéphane Rochoy .ppod_reg = 0xe1, /* FIXME Need to check for this group. */ 339*8e6ea10cSStéphane Rochoy .caps = NCT_GPIO_CAPS, 340*8e6ea10cSStéphane Rochoy .npins = 8, 341*8e6ea10cSStéphane Rochoy .iobase = 0xf0, 342*8e6ea10cSStéphane Rochoy }, 343*8e6ea10cSStéphane Rochoy { 344*8e6ea10cSStéphane Rochoy .grpnum = 2, 345*8e6ea10cSStéphane Rochoy .pinbits = { 0, 1, 2, 3, 4, 5, 6, 7 }, 346*8e6ea10cSStéphane Rochoy .enable_ldn = 0x09, 347*8e6ea10cSStéphane Rochoy .enable_reg = 0x30, 348*8e6ea10cSStéphane Rochoy .enable_mask = 0x01, 349*8e6ea10cSStéphane Rochoy .data_ldn = 0x09, 350*8e6ea10cSStéphane Rochoy .ppod_reg = 0xe1, /* FIXME Need to check for this group. */ 351*8e6ea10cSStéphane Rochoy .caps = NCT_GPIO_CAPS, 352*8e6ea10cSStéphane Rochoy .npins = 8, 353*8e6ea10cSStéphane Rochoy .iobase = 0xe0, 354*8e6ea10cSStéphane Rochoy }, 355*8e6ea10cSStéphane Rochoy { 356*8e6ea10cSStéphane Rochoy .grpnum = 3, 357*8e6ea10cSStéphane Rochoy .pinbits = { 0, 1, 2, 3, 4, 5, 6 }, 358*8e6ea10cSStéphane Rochoy .enable_ldn = 0x09, 359*8e6ea10cSStéphane Rochoy .enable_reg = 0x30, 360*8e6ea10cSStéphane Rochoy .enable_mask = 0x02, 361*8e6ea10cSStéphane Rochoy .data_ldn = 0x09, 362*8e6ea10cSStéphane Rochoy .ppod_reg = 0xe1, /* FIXME Need to check for this group. */ 363*8e6ea10cSStéphane Rochoy .caps = NCT_GPIO_CAPS, 364*8e6ea10cSStéphane Rochoy .npins = 7, 365*8e6ea10cSStéphane Rochoy .iobase = 0xe4, 366*8e6ea10cSStéphane Rochoy }, 367*8e6ea10cSStéphane Rochoy { 368*8e6ea10cSStéphane Rochoy .grpnum = 4, 369*8e6ea10cSStéphane Rochoy .pinbits = { 0, 1, 2, 3, 4, 5, 6, 7 }, 370*8e6ea10cSStéphane Rochoy .enable_ldn = 0x09, 371*8e6ea10cSStéphane Rochoy .enable_reg = 0x30, 372*8e6ea10cSStéphane Rochoy .enable_mask = 0x04, 373*8e6ea10cSStéphane Rochoy .data_ldn = 0x09, 374*8e6ea10cSStéphane Rochoy .ppod_reg = 0xe1, /* FIXME Need to check for this group. */ 375*8e6ea10cSStéphane Rochoy .caps = NCT_GPIO_CAPS, 376*8e6ea10cSStéphane Rochoy .npins = 8, 377*8e6ea10cSStéphane Rochoy .iobase = 0xf0, /* FIXME Page 344 say "F0~F2, E8", 378*8e6ea10cSStéphane Rochoy not "F0~F3". */ 379*8e6ea10cSStéphane Rochoy }, 380*8e6ea10cSStéphane Rochoy { 381*8e6ea10cSStéphane Rochoy .grpnum = 5, 382*8e6ea10cSStéphane Rochoy .pinbits = { 0, 1, 2, 3, 4, 5, 6, 7 }, 383*8e6ea10cSStéphane Rochoy .enable_ldn = 0x09, 384*8e6ea10cSStéphane Rochoy .enable_reg = 0x30, 385*8e6ea10cSStéphane Rochoy .enable_mask = 0x08, 386*8e6ea10cSStéphane Rochoy .data_ldn = 0x09, 387*8e6ea10cSStéphane Rochoy .ppod_reg = 0xe1, /* FIXME Need to check for this group. */ 388*8e6ea10cSStéphane Rochoy .caps = NCT_GPIO_CAPS, 389*8e6ea10cSStéphane Rochoy .npins = 8, 390*8e6ea10cSStéphane Rochoy .iobase = 0xf4, 391*8e6ea10cSStéphane Rochoy }, 392*8e6ea10cSStéphane Rochoy { 393*8e6ea10cSStéphane Rochoy .grpnum = 6, 394*8e6ea10cSStéphane Rochoy .pinbits = { 0, 1, 2, 3, 4, 5, 6, 7 }, 395*8e6ea10cSStéphane Rochoy .enable_ldn = 0x07, 396*8e6ea10cSStéphane Rochoy .enable_reg = 0x30, 397*8e6ea10cSStéphane Rochoy .enable_mask = 0x01, 398*8e6ea10cSStéphane Rochoy .data_ldn = 0x07, 399*8e6ea10cSStéphane Rochoy .ppod_reg = 0xe1, /* FIXME Need to check for this group. */ 400*8e6ea10cSStéphane Rochoy .caps = NCT_GPIO_CAPS, 401*8e6ea10cSStéphane Rochoy .npins = 8, 402*8e6ea10cSStéphane Rochoy .iobase = 0xf4, 403*8e6ea10cSStéphane Rochoy }, 404*8e6ea10cSStéphane Rochoy { 405*8e6ea10cSStéphane Rochoy .grpnum = 7, 406*8e6ea10cSStéphane Rochoy .pinbits = { 0, 1, 2, 3, 4, 5, 6, 7 }, 407*8e6ea10cSStéphane Rochoy .enable_ldn = 0x07, 408*8e6ea10cSStéphane Rochoy .enable_reg = 0x30, 409*8e6ea10cSStéphane Rochoy .enable_mask = 0x02, 410*8e6ea10cSStéphane Rochoy .data_ldn = 0x07, 411*8e6ea10cSStéphane Rochoy .ppod_reg = 0xe1, /* FIXME Need to check for this group. */ 412*8e6ea10cSStéphane Rochoy .caps = NCT_GPIO_CAPS, 413*8e6ea10cSStéphane Rochoy .npins = 8, 414*8e6ea10cSStéphane Rochoy .iobase = 0xe0, 415*8e6ea10cSStéphane Rochoy }, 416*8e6ea10cSStéphane Rochoy { 417*8e6ea10cSStéphane Rochoy .grpnum = 8, 418*8e6ea10cSStéphane Rochoy .pinbits = { 0, 1, 2, 3, 4, 5, 6, 7 }, 419*8e6ea10cSStéphane Rochoy .enable_ldn = 0x07, 420*8e6ea10cSStéphane Rochoy .enable_reg = 0x30, 421*8e6ea10cSStéphane Rochoy .enable_mask = 0x04, 422*8e6ea10cSStéphane Rochoy .data_ldn = 0x07, 423*8e6ea10cSStéphane Rochoy .ppod_reg = 0xe1, /* FIXME Need to check for this group. */ 424*8e6ea10cSStéphane Rochoy .caps = NCT_GPIO_CAPS, 425*8e6ea10cSStéphane Rochoy .npins = 8, 426*8e6ea10cSStéphane Rochoy .iobase = 0xe4, 427*8e6ea10cSStéphane Rochoy }, 428*8e6ea10cSStéphane Rochoy { 429*8e6ea10cSStéphane Rochoy .grpnum = 9, 430*8e6ea10cSStéphane Rochoy .pinbits = { 0, 1, 2, 3 }, 431*8e6ea10cSStéphane Rochoy .enable_ldn = 0x07, 432*8e6ea10cSStéphane Rochoy .enable_reg = 0x30, 433*8e6ea10cSStéphane Rochoy .enable_mask = 0x08, 434*8e6ea10cSStéphane Rochoy .data_ldn = 0x07, 435*8e6ea10cSStéphane Rochoy .ppod_reg = 0xe1, /* FIXME Need to check for this group. */ 436*8e6ea10cSStéphane Rochoy .caps = NCT_GPIO_CAPS, 437*8e6ea10cSStéphane Rochoy .npins = 4, 438*8e6ea10cSStéphane Rochoy .iobase = 0xe8, 439*8e6ea10cSStéphane Rochoy }, 440*8e6ea10cSStéphane Rochoy }, 441*8e6ea10cSStéphane Rochoy }, 442*8e6ea10cSStéphane Rochoy { 443*8e6ea10cSStéphane Rochoy .devid = 0xd42a, 444*8e6ea10cSStéphane Rochoy .extid = 2, 445*8e6ea10cSStéphane Rochoy .descr = "GPIO on Nuvoton NCT5585D", 446*8e6ea10cSStéphane Rochoy .ngroups = 6, 447*8e6ea10cSStéphane Rochoy .groups = { 448*8e6ea10cSStéphane Rochoy { 449*8e6ea10cSStéphane Rochoy .grpnum = 2, 450*8e6ea10cSStéphane Rochoy .pinbits = { 0, 1, 2, 3, 4, 5, 6 }, 451*8e6ea10cSStéphane Rochoy .enable_ldn = 0x09, 452*8e6ea10cSStéphane Rochoy .enable_reg = 0x30, 453*8e6ea10cSStéphane Rochoy .enable_mask = 0x01, 454*8e6ea10cSStéphane Rochoy .data_ldn = 0x09, 455*8e6ea10cSStéphane Rochoy .ppod_reg = 0xe1, 456*8e6ea10cSStéphane Rochoy .caps = NCT_GPIO_CAPS, 457*8e6ea10cSStéphane Rochoy .npins = 7, 458*8e6ea10cSStéphane Rochoy .iobase = 0xe0, 459*8e6ea10cSStéphane Rochoy }, 460*8e6ea10cSStéphane Rochoy { 461*8e6ea10cSStéphane Rochoy .grpnum = 3, 462*8e6ea10cSStéphane Rochoy .pinbits = { 1, 2, 3 }, 463*8e6ea10cSStéphane Rochoy .enable_ldn = 0x09, 464*8e6ea10cSStéphane Rochoy .enable_reg = 0x30, 465*8e6ea10cSStéphane Rochoy .enable_mask = 0x02, 466*8e6ea10cSStéphane Rochoy .data_ldn = 0x09, 467*8e6ea10cSStéphane Rochoy .ppod_reg = 0xe2, 468*8e6ea10cSStéphane Rochoy .caps = NCT_GPIO_CAPS, 469*8e6ea10cSStéphane Rochoy .npins = 3, 470*8e6ea10cSStéphane Rochoy .iobase = 0xe4, 471*8e6ea10cSStéphane Rochoy }, 472*8e6ea10cSStéphane Rochoy { 473*8e6ea10cSStéphane Rochoy .grpnum = 5, 474*8e6ea10cSStéphane Rochoy .pinbits = { 0, 2, 6, 7 }, 475*8e6ea10cSStéphane Rochoy .enable_ldn = 0x09, 476*8e6ea10cSStéphane Rochoy .enable_reg = 0x30, 477*8e6ea10cSStéphane Rochoy .enable_mask = 0x08, 478*8e6ea10cSStéphane Rochoy .data_ldn = 0x09, 479*8e6ea10cSStéphane Rochoy .ppod_reg = 0xe4, 480*8e6ea10cSStéphane Rochoy .caps = NCT_GPIO_CAPS, 481*8e6ea10cSStéphane Rochoy .npins = 4, 482*8e6ea10cSStéphane Rochoy .iobase = 0xf4, 483*8e6ea10cSStéphane Rochoy }, 484*8e6ea10cSStéphane Rochoy { 485*8e6ea10cSStéphane Rochoy .grpnum = 7, 486*8e6ea10cSStéphane Rochoy .pinbits = { 4 }, 487*8e6ea10cSStéphane Rochoy .enable_ldn = 0x07, 488*8e6ea10cSStéphane Rochoy .enable_reg = 0x30, 489*8e6ea10cSStéphane Rochoy .enable_mask = 0x02, 490*8e6ea10cSStéphane Rochoy .data_ldn = 0x07, 491*8e6ea10cSStéphane Rochoy .ppod_reg = 0xe6, 492*8e6ea10cSStéphane Rochoy .caps = NCT_GPIO_CAPS, 493*8e6ea10cSStéphane Rochoy .npins = 1, 494*8e6ea10cSStéphane Rochoy .iobase = 0xe0, 495*8e6ea10cSStéphane Rochoy }, 496*8e6ea10cSStéphane Rochoy { 497*8e6ea10cSStéphane Rochoy .grpnum = 8, 498*8e6ea10cSStéphane Rochoy .pinbits = { 0, 1, 2, 3, 4, 5, 6, 7 }, 499*8e6ea10cSStéphane Rochoy .enable_ldn = 0x07, 500*8e6ea10cSStéphane Rochoy .enable_reg = 0x30, 501*8e6ea10cSStéphane Rochoy .enable_mask = 0x04, 502*8e6ea10cSStéphane Rochoy .data_ldn = 0x07, 503*8e6ea10cSStéphane Rochoy .ppod_reg = 0xe7, 504*8e6ea10cSStéphane Rochoy .caps = NCT_GPIO_CAPS, 505*8e6ea10cSStéphane Rochoy .npins = 8, 506*8e6ea10cSStéphane Rochoy .iobase = 0xe4, 507*8e6ea10cSStéphane Rochoy }, 508*8e6ea10cSStéphane Rochoy { 509*8e6ea10cSStéphane Rochoy .grpnum = 9, 510*8e6ea10cSStéphane Rochoy .pinbits = { 0, 2 }, 511*8e6ea10cSStéphane Rochoy .enable_ldn = 0x07, 512*8e6ea10cSStéphane Rochoy .enable_reg = 0x30, 513*8e6ea10cSStéphane Rochoy .enable_mask = 0x08, 514*8e6ea10cSStéphane Rochoy .data_ldn = 0x07, 515*8e6ea10cSStéphane Rochoy .ppod_reg = 0xea, 516*8e6ea10cSStéphane Rochoy .caps = NCT_GPIO_CAPS, 517*8e6ea10cSStéphane Rochoy .npins = 2, 518*8e6ea10cSStéphane Rochoy .iobase = 0xe8, 519*8e6ea10cSStéphane Rochoy }, 520*8e6ea10cSStéphane Rochoy }, 521*8e6ea10cSStéphane Rochoy }, 522*8e6ea10cSStéphane Rochoy { 523*8e6ea10cSStéphane Rochoy .devid = 0xc562, 524*8e6ea10cSStéphane Rochoy .descr = "GPIO on Nuvoton NCT6779D", 525*8e6ea10cSStéphane Rochoy .ngroups = 9, 526*8e6ea10cSStéphane Rochoy .groups = { 527*8e6ea10cSStéphane Rochoy { 528*8e6ea10cSStéphane Rochoy .grpnum = 0, 529*8e6ea10cSStéphane Rochoy .pinbits = { 0, 1, 2, 3, 4, 5, 6, 7 }, 530*8e6ea10cSStéphane Rochoy .enable_ldn = 0x08, 531*8e6ea10cSStéphane Rochoy .enable_reg = 0x30, 532*8e6ea10cSStéphane Rochoy .enable_mask = 0x01, 533*8e6ea10cSStéphane Rochoy .data_ldn = 0x08, 534*8e6ea10cSStéphane Rochoy .ppod_reg = 0xe0, /* FIXME Need to check for this group. */ 535*8e6ea10cSStéphane Rochoy .caps = NCT_GPIO_CAPS, 536*8e6ea10cSStéphane Rochoy .npins = 8, 537*8e6ea10cSStéphane Rochoy .iobase = 0xe0, 538*8e6ea10cSStéphane Rochoy }, 539*8e6ea10cSStéphane Rochoy { 540*8e6ea10cSStéphane Rochoy .grpnum = 1, 541*8e6ea10cSStéphane Rochoy .pinbits = { 0, 1, 2, 3, 4, 5, 6, 7 }, 542*8e6ea10cSStéphane Rochoy .enable_ldn = 0x09, 543*8e6ea10cSStéphane Rochoy .enable_reg = 0x30, 544*8e6ea10cSStéphane Rochoy .enable_mask = 0x01, 545*8e6ea10cSStéphane Rochoy .data_ldn = 0x08, 546*8e6ea10cSStéphane Rochoy .ppod_reg = 0xe1, /* FIXME Need to check for this group. */ 547*8e6ea10cSStéphane Rochoy .caps = NCT_GPIO_CAPS, 548*8e6ea10cSStéphane Rochoy .npins = 8, 549*8e6ea10cSStéphane Rochoy .iobase = 0xf0, 550*8e6ea10cSStéphane Rochoy }, 551*8e6ea10cSStéphane Rochoy { 552*8e6ea10cSStéphane Rochoy .grpnum = 2, 553*8e6ea10cSStéphane Rochoy .pinbits = { 0, 1, 2, 3, 4, 5, 6, 7 }, 554*8e6ea10cSStéphane Rochoy .enable_ldn = 0x09, 555*8e6ea10cSStéphane Rochoy .enable_reg = 0x30, 556*8e6ea10cSStéphane Rochoy .enable_mask = 0x01, 557*8e6ea10cSStéphane Rochoy .data_ldn = 0x09, 558*8e6ea10cSStéphane Rochoy .ppod_reg = 0xe1, /* FIXME Need to check for this group. */ 559*8e6ea10cSStéphane Rochoy .caps = NCT_GPIO_CAPS, 560*8e6ea10cSStéphane Rochoy .npins = 8, 561*8e6ea10cSStéphane Rochoy .iobase = 0xe0, 562*8e6ea10cSStéphane Rochoy }, 563*8e6ea10cSStéphane Rochoy { 564*8e6ea10cSStéphane Rochoy .grpnum = 3, 565*8e6ea10cSStéphane Rochoy .pinbits = { 0, 1, 2, 3, 4, 5, 6 }, 566*8e6ea10cSStéphane Rochoy .enable_ldn = 0x09, 567*8e6ea10cSStéphane Rochoy .enable_reg = 0x30, 568*8e6ea10cSStéphane Rochoy .enable_mask = 0x02, 569*8e6ea10cSStéphane Rochoy .data_ldn = 0x09, 570*8e6ea10cSStéphane Rochoy .ppod_reg = 0xe1, /* FIXME Need to check for this group. */ 571*8e6ea10cSStéphane Rochoy .caps = NCT_GPIO_CAPS, 572*8e6ea10cSStéphane Rochoy .npins = 7, 573*8e6ea10cSStéphane Rochoy .iobase = 0xe4, 574*8e6ea10cSStéphane Rochoy }, 575*8e6ea10cSStéphane Rochoy { 576*8e6ea10cSStéphane Rochoy .grpnum = 4, 577*8e6ea10cSStéphane Rochoy .pinbits = { 0, 1, 2, 3, 4, 5, 6, 7 }, 578*8e6ea10cSStéphane Rochoy .enable_ldn = 0x09, 579*8e6ea10cSStéphane Rochoy .enable_reg = 0x30, 580*8e6ea10cSStéphane Rochoy .enable_mask = 0x04, 581*8e6ea10cSStéphane Rochoy .data_ldn = 0x09, 582*8e6ea10cSStéphane Rochoy .ppod_reg = 0xe1, /* FIXME Need to check for this group. */ 583*8e6ea10cSStéphane Rochoy .caps = NCT_GPIO_CAPS, 584*8e6ea10cSStéphane Rochoy .npins = 8, 585*8e6ea10cSStéphane Rochoy .iobase = 0xf0, 586*8e6ea10cSStéphane Rochoy }, 587*8e6ea10cSStéphane Rochoy { 588*8e6ea10cSStéphane Rochoy .grpnum = 5, 589*8e6ea10cSStéphane Rochoy .pinbits = { 0, 1, 2, 3, 4, 5, 6, 7 }, 590*8e6ea10cSStéphane Rochoy .enable_ldn = 0x09, 591*8e6ea10cSStéphane Rochoy .enable_reg = 0x30, 592*8e6ea10cSStéphane Rochoy .enable_mask = 0x08, 593*8e6ea10cSStéphane Rochoy .data_ldn = 0x09, 594*8e6ea10cSStéphane Rochoy .ppod_reg = 0xe1, /* FIXME Need to check for this group. */ 595*8e6ea10cSStéphane Rochoy .caps = NCT_GPIO_CAPS, 596*8e6ea10cSStéphane Rochoy .npins = 8, 597*8e6ea10cSStéphane Rochoy .iobase = 0xf4, 598*8e6ea10cSStéphane Rochoy }, 599*8e6ea10cSStéphane Rochoy { 600*8e6ea10cSStéphane Rochoy .grpnum = 6, 601*8e6ea10cSStéphane Rochoy .pinbits = { 0, 1, 2, 3, 4, 5, 6, 7 }, 602*8e6ea10cSStéphane Rochoy .enable_ldn = 0x09, 603*8e6ea10cSStéphane Rochoy .enable_reg = 0x30, 604*8e6ea10cSStéphane Rochoy .enable_mask = 0x01, 605*8e6ea10cSStéphane Rochoy .data_ldn = 0x07, 606*8e6ea10cSStéphane Rochoy .ppod_reg = 0xe1, /* FIXME Need to check for this group. */ 607*8e6ea10cSStéphane Rochoy .caps = NCT_GPIO_CAPS, 608*8e6ea10cSStéphane Rochoy .npins = 8, 609*8e6ea10cSStéphane Rochoy .iobase = 0xf4, 610*8e6ea10cSStéphane Rochoy }, 611*8e6ea10cSStéphane Rochoy { 612*8e6ea10cSStéphane Rochoy .grpnum = 7, 613*8e6ea10cSStéphane Rochoy .pinbits = { 0, 1, 2, 3, 4, 5, 6 }, 614*8e6ea10cSStéphane Rochoy .enable_ldn = 0x09, 615*8e6ea10cSStéphane Rochoy .enable_reg = 0x30, 616*8e6ea10cSStéphane Rochoy .enable_mask = 0x02, 617*8e6ea10cSStéphane Rochoy .data_ldn = 0x07, 618*8e6ea10cSStéphane Rochoy .ppod_reg = 0xe1, /* FIXME Need to check for this group. */ 619*8e6ea10cSStéphane Rochoy .caps = NCT_GPIO_CAPS, 620*8e6ea10cSStéphane Rochoy .npins = 7, 621*8e6ea10cSStéphane Rochoy .iobase = 0xe0, 622*8e6ea10cSStéphane Rochoy }, 623*8e6ea10cSStéphane Rochoy { 624*8e6ea10cSStéphane Rochoy .grpnum = 8, 625*8e6ea10cSStéphane Rochoy .pinbits = { 0, 1, 2, 3, 4, 5, 6, 7 }, 626*8e6ea10cSStéphane Rochoy .enable_ldn = 0x09, 627*8e6ea10cSStéphane Rochoy .enable_reg = 0x30, 628*8e6ea10cSStéphane Rochoy .enable_mask = 0x04, 629*8e6ea10cSStéphane Rochoy .data_ldn = 0x07, 630*8e6ea10cSStéphane Rochoy .ppod_reg = 0xe1, /* FIXME Need to check for this group. */ 631*8e6ea10cSStéphane Rochoy .caps = NCT_GPIO_CAPS, 632*8e6ea10cSStéphane Rochoy .npins = 8, 633*8e6ea10cSStéphane Rochoy .iobase = 0xe4, 634*8e6ea10cSStéphane Rochoy }, 635*8e6ea10cSStéphane Rochoy }, 636*8e6ea10cSStéphane Rochoy }, 637*8e6ea10cSStéphane Rochoy { 638*8e6ea10cSStéphane Rochoy .devid = 0xd282, 639*8e6ea10cSStéphane Rochoy .descr = "GPIO on Nuvoton NCT6112D/NCT6114D/NCT6116D", 640*8e6ea10cSStéphane Rochoy .ngroups = 2, 641*8e6ea10cSStéphane Rochoy .groups = { 642*8e6ea10cSStéphane Rochoy { 643*8e6ea10cSStéphane Rochoy .grpnum = 0, 644*8e6ea10cSStéphane Rochoy .pinbits = { 0, 1, 2, 3, 4, 5, 6, 7 }, 645*8e6ea10cSStéphane Rochoy .enable_ldn = 0x07, 646*8e6ea10cSStéphane Rochoy .enable_reg = 0x30, 647*8e6ea10cSStéphane Rochoy .enable_mask = 0x01, 648*8e6ea10cSStéphane Rochoy .data_ldn = 0x07, 649*8e6ea10cSStéphane Rochoy .ppod_reg = 0xe0, /* FIXME Need to check for this group. */ 650*8e6ea10cSStéphane Rochoy .caps = NCT_GPIO_CAPS, 651*8e6ea10cSStéphane Rochoy .npins = 8, 652*8e6ea10cSStéphane Rochoy .iobase = 0xe0, 653*8e6ea10cSStéphane Rochoy }, 654*8e6ea10cSStéphane Rochoy { 655*8e6ea10cSStéphane Rochoy .grpnum = 1, 656*8e6ea10cSStéphane Rochoy .pinbits = { 0, 1, 2, 3, 4, 5, 6, 7 }, 657*8e6ea10cSStéphane Rochoy .enable_ldn = 0x07, 658*8e6ea10cSStéphane Rochoy .enable_reg = 0x30, 659*8e6ea10cSStéphane Rochoy .enable_mask = 0x02, 660*8e6ea10cSStéphane Rochoy .data_ldn = 0x07, 661*8e6ea10cSStéphane Rochoy .ppod_reg = 0xe1, /* FIXME Need to check for this group. */ 662*8e6ea10cSStéphane Rochoy .caps = NCT_GPIO_CAPS, 663*8e6ea10cSStéphane Rochoy .npins = 8, 664*8e6ea10cSStéphane Rochoy .iobase = 0xe4, 665*8e6ea10cSStéphane Rochoy }, 666*8e6ea10cSStéphane Rochoy { 667*8e6ea10cSStéphane Rochoy .grpnum = 2, 668*8e6ea10cSStéphane Rochoy .pinbits = { 0, 1, 2, 3, 4, 5, 6, 7 }, 669*8e6ea10cSStéphane Rochoy .enable_ldn = 0x07, 670*8e6ea10cSStéphane Rochoy .enable_reg = 0x30, 671*8e6ea10cSStéphane Rochoy .enable_mask = 0x04, 672*8e6ea10cSStéphane Rochoy .data_ldn = 0x07, 673*8e6ea10cSStéphane Rochoy .ppod_reg = 0xe1, /* FIXME Need to check for this group. */ 674*8e6ea10cSStéphane Rochoy .caps = NCT_GPIO_CAPS, 675*8e6ea10cSStéphane Rochoy .npins = 8, 676*8e6ea10cSStéphane Rochoy .iobase = 0xe8, 677*8e6ea10cSStéphane Rochoy }, 678*8e6ea10cSStéphane Rochoy { 679*8e6ea10cSStéphane Rochoy .grpnum = 3, 680*8e6ea10cSStéphane Rochoy .pinbits = { 0, 1, 2, 3, 4, 5, 6, 7 }, 681*8e6ea10cSStéphane Rochoy .enable_ldn = 0x07, 682*8e6ea10cSStéphane Rochoy .enable_reg = 0x30, 683*8e6ea10cSStéphane Rochoy .enable_mask = 0x08, 684*8e6ea10cSStéphane Rochoy .data_ldn = 0x07, 685*8e6ea10cSStéphane Rochoy .ppod_reg = 0xe1, /* FIXME Need to check for this group. */ 686*8e6ea10cSStéphane Rochoy .caps = NCT_GPIO_CAPS, 687*8e6ea10cSStéphane Rochoy .npins = 8, 688*8e6ea10cSStéphane Rochoy .iobase = 0xec, 689*8e6ea10cSStéphane Rochoy }, 690*8e6ea10cSStéphane Rochoy { 691*8e6ea10cSStéphane Rochoy .grpnum = 4, 692*8e6ea10cSStéphane Rochoy .pinbits = { 0, 1, 2, 3, 4, 5, 6, 7 }, 693*8e6ea10cSStéphane Rochoy .enable_ldn = 0x07, 694*8e6ea10cSStéphane Rochoy .enable_reg = 0x30, 695*8e6ea10cSStéphane Rochoy .enable_mask = 0x10, 696*8e6ea10cSStéphane Rochoy .data_ldn = 0x07, 697*8e6ea10cSStéphane Rochoy .ppod_reg = 0xe1, /* FIXME Need to check for this group. */ 698*8e6ea10cSStéphane Rochoy .caps = NCT_GPIO_CAPS, 699*8e6ea10cSStéphane Rochoy .npins = 8, 700*8e6ea10cSStéphane Rochoy .iobase = 0xf0, 701*8e6ea10cSStéphane Rochoy }, 702*8e6ea10cSStéphane Rochoy { 703*8e6ea10cSStéphane Rochoy .grpnum = 5, 704*8e6ea10cSStéphane Rochoy .pinbits = { 0, 1, 2, 3, 4, 5, 6, 7 }, 705*8e6ea10cSStéphane Rochoy .enable_ldn = 0x07, 706*8e6ea10cSStéphane Rochoy .enable_reg = 0x30, 707*8e6ea10cSStéphane Rochoy .enable_mask = 0x20, 708*8e6ea10cSStéphane Rochoy .data_ldn = 0x07, 709*8e6ea10cSStéphane Rochoy .ppod_reg = 0xe1, /* FIXME Need to check for this group. */ 710*8e6ea10cSStéphane Rochoy .caps = NCT_GPIO_CAPS, 711*8e6ea10cSStéphane Rochoy .npins = 8, 712*8e6ea10cSStéphane Rochoy .iobase = 0xf4, 713*8e6ea10cSStéphane Rochoy }, 714*8e6ea10cSStéphane Rochoy { 715*8e6ea10cSStéphane Rochoy .grpnum = 6, 716*8e6ea10cSStéphane Rochoy .pinbits = { 0, 1, 2, 3, 4, 5, 6, 7 }, 717*8e6ea10cSStéphane Rochoy .enable_ldn = 0x07, 718*8e6ea10cSStéphane Rochoy .enable_reg = 0x30, 719*8e6ea10cSStéphane Rochoy .enable_mask = 0x40, 720*8e6ea10cSStéphane Rochoy .data_ldn = 0x07, 721*8e6ea10cSStéphane Rochoy .ppod_reg = 0xe1, /* FIXME Need to check for this group. */ 722*8e6ea10cSStéphane Rochoy .caps = NCT_GPIO_CAPS, 723*8e6ea10cSStéphane Rochoy .npins = 8, 724*8e6ea10cSStéphane Rochoy .iobase = 0xf8, 725*8e6ea10cSStéphane Rochoy }, 726*8e6ea10cSStéphane Rochoy { 727*8e6ea10cSStéphane Rochoy .grpnum = 7, 728*8e6ea10cSStéphane Rochoy .pinbits = { 0, 1, 2, 3, 4, 5, 6, 7 }, 729*8e6ea10cSStéphane Rochoy .enable_ldn = 0x07, 730*8e6ea10cSStéphane Rochoy .enable_reg = 0x30, 731*8e6ea10cSStéphane Rochoy .enable_mask = 0x80, 732*8e6ea10cSStéphane Rochoy .data_ldn = 0x07, 733*8e6ea10cSStéphane Rochoy .ppod_reg = 0xe1, /* FIXME Need to check for this group. */ 734*8e6ea10cSStéphane Rochoy .caps = NCT_GPIO_CAPS, 735*8e6ea10cSStéphane Rochoy .npins = 8, 736*8e6ea10cSStéphane Rochoy .iobase = 0xfc, 737*8e6ea10cSStéphane Rochoy }, 738*8e6ea10cSStéphane Rochoy { 739*8e6ea10cSStéphane Rochoy .grpnum = 8, 740*8e6ea10cSStéphane Rochoy .pinbits = { 0, 1, 2, 3, 4, 5, 6, 7 }, 741*8e6ea10cSStéphane Rochoy .enable_ldn = 0x09, 742*8e6ea10cSStéphane Rochoy .enable_reg = 0x30, 743*8e6ea10cSStéphane Rochoy .enable_mask = 0x01, 744*8e6ea10cSStéphane Rochoy .data_ldn = 0x09, 745*8e6ea10cSStéphane Rochoy .ppod_reg = 0xe1, /* FIXME Need to check for this group. */ 746*8e6ea10cSStéphane Rochoy .caps = NCT_GPIO_CAPS, 747*8e6ea10cSStéphane Rochoy .npins = 8, 748*8e6ea10cSStéphane Rochoy .iobase = 0xf0, 749*8e6ea10cSStéphane Rochoy }, 750*8e6ea10cSStéphane Rochoy }, 751*8e6ea10cSSté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 1042*8e6ea10cSSté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, 1169*8e6ea10cSSté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++) { 12037f8d2ed0SStéphane Rochoy sc->npins += gp->npins; 12047f8d2ed0SStéphane Rochoy for (i = 0; i < gp->npins; i++, pin_num++) { 12057f8d2ed0SStéphane Rochoy struct gpio_pin *pin; 12067f8d2ed0SStéphane Rochoy 12077f8d2ed0SStéphane Rochoy sc->pinmap[pin_num].group = gp; 12087f8d2ed0SStéphane Rochoy sc->pinmap[pin_num].grpnum = gp->grpnum; 12097f8d2ed0SStéphane Rochoy sc->pinmap[pin_num].bit = gp->pinbits[i]; 12107f8d2ed0SStéphane Rochoy 12117f8d2ed0SStéphane Rochoy sc->grpmap[gp->grpnum] = gp; 12127f8d2ed0SStéphane Rochoy 12137f8d2ed0SStéphane Rochoy pin = &sc->pins[pin_num]; 12147f8d2ed0SStéphane Rochoy pin->gp_pin = pin_num; 12157f8d2ed0SStéphane Rochoy pin->gp_caps = gp->caps; 12167f8d2ed0SStéphane Rochoy pin->gp_flags = 0; 12177f8d2ed0SStéphane Rochoy 12187f8d2ed0SStéphane Rochoy snprintf(pin->gp_name, GPIOMAXNAME, "GPIO%u%u", 12197f8d2ed0SStéphane Rochoy gp->grpnum, gp->pinbits[i]); 12207f8d2ed0SStéphane Rochoy 12217f8d2ed0SStéphane Rochoy if (nct_pin_is_input(sc, pin_num)) 12227f8d2ed0SStéphane Rochoy pin->gp_flags |= GPIO_PIN_INPUT; 12237f8d2ed0SStéphane Rochoy else 12247f8d2ed0SStéphane Rochoy pin->gp_flags |= GPIO_PIN_OUTPUT; 12257f8d2ed0SStéphane Rochoy 12267f8d2ed0SStéphane Rochoy if (nct_pin_is_opendrain(sc, pin_num)) 12277f8d2ed0SStéphane Rochoy pin->gp_flags |= GPIO_PIN_OPENDRAIN; 12287f8d2ed0SStéphane Rochoy else 12297f8d2ed0SStéphane Rochoy pin->gp_flags |= GPIO_PIN_PUSHPULL; 12307f8d2ed0SStéphane Rochoy 12317f8d2ed0SStéphane Rochoy if (nct_pin_is_inverted(sc, pin_num)) 12327f8d2ed0SStéphane Rochoy pin->gp_flags |= (GPIO_PIN_INVIN | GPIO_PIN_INVOUT); 12337f8d2ed0SStéphane Rochoy } 12347f8d2ed0SStéphane Rochoy } 12357f8d2ed0SStéphane Rochoy NCT_VERBOSE_PRINTF(dev, "%d pins available\n", sc->npins); 1236155514eaSAndriy Gapon 1237155514eaSAndriy Gapon /* 1238155514eaSAndriy Gapon * Caching input values is meaningless as an input can be changed at any 1239155514eaSAndriy Gapon * time by an external agent. But outputs are controlled by this 1240155514eaSAndriy Gapon * driver, so it can cache their state. Also, the hardware remembers 1241155514eaSAndriy Gapon * the output state of a pin when the pin is switched to input mode and 1242155514eaSAndriy Gapon * then back to output mode. So, the cache stays valid. 1243155514eaSAndriy Gapon * The only problem is with pins that are in input mode at the attach 1244155514eaSAndriy Gapon * time. For them the output state is not known until it is set by the 1245155514eaSAndriy Gapon * driver for the first time. 1246155514eaSAndriy Gapon * 'out' and 'out_known' bits form a tri-state output cache: 1247155514eaSAndriy Gapon * |-----+-----------+---------| 1248155514eaSAndriy Gapon * | out | out_known | cache | 1249155514eaSAndriy Gapon * |-----+-----------+---------| 1250155514eaSAndriy Gapon * | X | 0 | invalid | 1251155514eaSAndriy Gapon * | 0 | 1 | 0 | 1252155514eaSAndriy Gapon * | 1 | 1 | 1 | 1253155514eaSAndriy Gapon * |-----+-----------+---------| 1254155514eaSAndriy Gapon */ 12557f8d2ed0SStéphane Rochoy for (g = 0, gp = sc->nctdevp->groups; g < sc->nctdevp->ngroups; g++, gp++) { 12567f8d2ed0SStéphane Rochoy sc->cache.inv[gp->grpnum] = nct_read_reg(sc, REG_INV, gp->grpnum); 12577f8d2ed0SStéphane Rochoy sc->cache.ior[gp->grpnum] = nct_read_reg(sc, REG_IOR, gp->grpnum); 12587f8d2ed0SStéphane Rochoy sc->cache.out[gp->grpnum] = nct_read_reg(sc, REG_DAT, gp->grpnum); 12597f8d2ed0SStéphane Rochoy sc->cache.out_known[gp->grpnum] = ~sc->cache.ior[gp->grpnum]; 12606b7b2d80SAdrian Chadd } 12617f8d2ed0SStéphane Rochoy 12626b7b2d80SAdrian Chadd GPIO_UNLOCK(sc); 12636b7b2d80SAdrian Chadd 12646b7b2d80SAdrian Chadd sc->busdev = gpiobus_attach_bus(dev); 12656b7b2d80SAdrian Chadd if (sc->busdev == NULL) { 12667f8d2ed0SStéphane Rochoy device_printf(dev, "failed to attach to gpiobus\n"); 12676b7b2d80SAdrian Chadd GPIO_LOCK_DESTROY(sc); 12686b7b2d80SAdrian Chadd return (ENXIO); 12696b7b2d80SAdrian Chadd } 12706b7b2d80SAdrian Chadd 12716b7b2d80SAdrian Chadd return (0); 12726b7b2d80SAdrian Chadd } 12736b7b2d80SAdrian Chadd 12746b7b2d80SAdrian Chadd static int 12756b7b2d80SAdrian Chadd nct_detach(device_t dev) 12766b7b2d80SAdrian Chadd { 12776b7b2d80SAdrian Chadd struct nct_softc *sc; 12786b7b2d80SAdrian Chadd 12796b7b2d80SAdrian Chadd sc = device_get_softc(dev); 12806b7b2d80SAdrian Chadd gpiobus_detach_bus(dev); 12816b7b2d80SAdrian Chadd 1282155514eaSAndriy Gapon if (sc->iores != NULL) 1283155514eaSAndriy Gapon bus_release_resource(dev, SYS_RES_IOPORT, sc->iorid, sc->iores); 12846b7b2d80SAdrian Chadd GPIO_ASSERT_UNLOCKED(sc); 12856b7b2d80SAdrian Chadd GPIO_LOCK_DESTROY(sc); 12866b7b2d80SAdrian Chadd 12876b7b2d80SAdrian Chadd return (0); 12886b7b2d80SAdrian Chadd } 12896b7b2d80SAdrian Chadd 12906b7b2d80SAdrian Chadd static device_t 12916b7b2d80SAdrian Chadd nct_gpio_get_bus(device_t dev) 12926b7b2d80SAdrian Chadd { 12936b7b2d80SAdrian Chadd struct nct_softc *sc; 12946b7b2d80SAdrian Chadd 12956b7b2d80SAdrian Chadd sc = device_get_softc(dev); 12966b7b2d80SAdrian Chadd 12976b7b2d80SAdrian Chadd return (sc->busdev); 12986b7b2d80SAdrian Chadd } 12996b7b2d80SAdrian Chadd 13006b7b2d80SAdrian Chadd static int 13017f8d2ed0SStéphane Rochoy nct_gpio_pin_max(device_t dev, int *maxpin) 13026b7b2d80SAdrian Chadd { 13037f8d2ed0SStéphane Rochoy struct nct_softc *sc; 13046b7b2d80SAdrian Chadd 13057f8d2ed0SStéphane Rochoy sc = device_get_softc(dev); 13067f8d2ed0SStéphane Rochoy *maxpin = sc->npins - 1; 13076b7b2d80SAdrian Chadd return (0); 13086b7b2d80SAdrian Chadd } 13096b7b2d80SAdrian Chadd 13106b7b2d80SAdrian Chadd static int 13116b7b2d80SAdrian Chadd nct_gpio_pin_set(device_t dev, uint32_t pin_num, uint32_t pin_value) 13126b7b2d80SAdrian Chadd { 13136b7b2d80SAdrian Chadd struct nct_softc *sc; 13146b7b2d80SAdrian Chadd 13157f8d2ed0SStéphane Rochoy sc = device_get_softc(dev); 13167f8d2ed0SStéphane Rochoy 13177f8d2ed0SStéphane Rochoy if (!NCT_PIN_IS_VALID(sc, pin_num)) 13186b7b2d80SAdrian Chadd return (EINVAL); 13196b7b2d80SAdrian Chadd 13206b7b2d80SAdrian Chadd GPIO_LOCK(sc); 1321155514eaSAndriy Gapon if ((sc->pins[pin_num].gp_flags & GPIO_PIN_OUTPUT) == 0) { 1322155514eaSAndriy Gapon GPIO_UNLOCK(sc); 1323155514eaSAndriy Gapon return (EINVAL); 1324155514eaSAndriy Gapon } 13256b7b2d80SAdrian Chadd nct_write_pin(sc, pin_num, pin_value); 13266b7b2d80SAdrian Chadd GPIO_UNLOCK(sc); 13276b7b2d80SAdrian Chadd 13286b7b2d80SAdrian Chadd return (0); 13296b7b2d80SAdrian Chadd } 13306b7b2d80SAdrian Chadd 13316b7b2d80SAdrian Chadd static int 13326b7b2d80SAdrian Chadd nct_gpio_pin_get(device_t dev, uint32_t pin_num, uint32_t *pin_value) 13336b7b2d80SAdrian Chadd { 13346b7b2d80SAdrian Chadd struct nct_softc *sc; 13356b7b2d80SAdrian Chadd 13367f8d2ed0SStéphane Rochoy sc = device_get_softc(dev); 13377f8d2ed0SStéphane Rochoy 13387f8d2ed0SStéphane Rochoy if (!NCT_PIN_IS_VALID(sc, pin_num)) 13396b7b2d80SAdrian Chadd return (EINVAL); 13406b7b2d80SAdrian Chadd 13416b7b2d80SAdrian Chadd GPIO_ASSERT_UNLOCKED(sc); 13426b7b2d80SAdrian Chadd GPIO_LOCK(sc); 13436b7b2d80SAdrian Chadd *pin_value = nct_read_pin(sc, pin_num); 13446b7b2d80SAdrian Chadd GPIO_UNLOCK(sc); 13456b7b2d80SAdrian Chadd 13466b7b2d80SAdrian Chadd return (0); 13476b7b2d80SAdrian Chadd } 13486b7b2d80SAdrian Chadd 13496b7b2d80SAdrian Chadd static int 13506b7b2d80SAdrian Chadd nct_gpio_pin_toggle(device_t dev, uint32_t pin_num) 13516b7b2d80SAdrian Chadd { 13526b7b2d80SAdrian Chadd struct nct_softc *sc; 13536b7b2d80SAdrian Chadd 13547f8d2ed0SStéphane Rochoy sc = device_get_softc(dev); 13557f8d2ed0SStéphane Rochoy 13567f8d2ed0SStéphane Rochoy if (!NCT_PIN_IS_VALID(sc, pin_num)) 13576b7b2d80SAdrian Chadd return (EINVAL); 13586b7b2d80SAdrian Chadd 13596b7b2d80SAdrian Chadd GPIO_ASSERT_UNLOCKED(sc); 13606b7b2d80SAdrian Chadd GPIO_LOCK(sc); 1361155514eaSAndriy Gapon if ((sc->pins[pin_num].gp_flags & GPIO_PIN_OUTPUT) == 0) { 1362155514eaSAndriy Gapon GPIO_UNLOCK(sc); 1363155514eaSAndriy Gapon return (EINVAL); 1364155514eaSAndriy Gapon } 13656b7b2d80SAdrian Chadd if (nct_read_pin(sc, pin_num)) 13666b7b2d80SAdrian Chadd nct_write_pin(sc, pin_num, 0); 13676b7b2d80SAdrian Chadd else 13686b7b2d80SAdrian Chadd nct_write_pin(sc, pin_num, 1); 13696b7b2d80SAdrian Chadd 13706b7b2d80SAdrian Chadd GPIO_UNLOCK(sc); 13716b7b2d80SAdrian Chadd 13726b7b2d80SAdrian Chadd return (0); 13736b7b2d80SAdrian Chadd } 13746b7b2d80SAdrian Chadd 13756b7b2d80SAdrian Chadd static int 13766b7b2d80SAdrian Chadd nct_gpio_pin_getcaps(device_t dev, uint32_t pin_num, uint32_t *caps) 13776b7b2d80SAdrian Chadd { 13786b7b2d80SAdrian Chadd struct nct_softc *sc; 13796b7b2d80SAdrian Chadd 13807f8d2ed0SStéphane Rochoy sc = device_get_softc(dev); 13817f8d2ed0SStéphane Rochoy 13827f8d2ed0SStéphane Rochoy if (!NCT_PIN_IS_VALID(sc, pin_num)) 13836b7b2d80SAdrian Chadd return (EINVAL); 13846b7b2d80SAdrian Chadd 13856b7b2d80SAdrian Chadd GPIO_ASSERT_UNLOCKED(sc); 13866b7b2d80SAdrian Chadd GPIO_LOCK(sc); 13876b7b2d80SAdrian Chadd *caps = sc->pins[pin_num].gp_caps; 13886b7b2d80SAdrian Chadd GPIO_UNLOCK(sc); 13896b7b2d80SAdrian Chadd 13906b7b2d80SAdrian Chadd return (0); 13916b7b2d80SAdrian Chadd } 13926b7b2d80SAdrian Chadd 13936b7b2d80SAdrian Chadd static int 13946b7b2d80SAdrian Chadd nct_gpio_pin_getflags(device_t dev, uint32_t pin_num, uint32_t *flags) 13956b7b2d80SAdrian Chadd { 13966b7b2d80SAdrian Chadd struct nct_softc *sc; 13976b7b2d80SAdrian Chadd 13987f8d2ed0SStéphane Rochoy sc = device_get_softc(dev); 13997f8d2ed0SStéphane Rochoy 14007f8d2ed0SStéphane Rochoy if (!NCT_PIN_IS_VALID(sc, pin_num)) 14016b7b2d80SAdrian Chadd return (EINVAL); 14026b7b2d80SAdrian Chadd 14036b7b2d80SAdrian Chadd GPIO_ASSERT_UNLOCKED(sc); 14046b7b2d80SAdrian Chadd GPIO_LOCK(sc); 14056b7b2d80SAdrian Chadd *flags = sc->pins[pin_num].gp_flags; 14066b7b2d80SAdrian Chadd GPIO_UNLOCK(sc); 14076b7b2d80SAdrian Chadd 14086b7b2d80SAdrian Chadd return (0); 14096b7b2d80SAdrian Chadd } 14106b7b2d80SAdrian Chadd 14116b7b2d80SAdrian Chadd static int 14126b7b2d80SAdrian Chadd nct_gpio_pin_getname(device_t dev, uint32_t pin_num, char *name) 14136b7b2d80SAdrian Chadd { 14146b7b2d80SAdrian Chadd struct nct_softc *sc; 14156b7b2d80SAdrian Chadd 14167f8d2ed0SStéphane Rochoy sc = device_get_softc(dev); 14177f8d2ed0SStéphane Rochoy 14187f8d2ed0SStéphane Rochoy if (!NCT_PIN_IS_VALID(sc, pin_num)) 14196b7b2d80SAdrian Chadd return (EINVAL); 14206b7b2d80SAdrian Chadd 14216b7b2d80SAdrian Chadd GPIO_ASSERT_UNLOCKED(sc); 14226b7b2d80SAdrian Chadd GPIO_LOCK(sc); 14236b7b2d80SAdrian Chadd memcpy(name, sc->pins[pin_num].gp_name, GPIOMAXNAME); 14246b7b2d80SAdrian Chadd GPIO_UNLOCK(sc); 14256b7b2d80SAdrian Chadd 14266b7b2d80SAdrian Chadd return (0); 14276b7b2d80SAdrian Chadd } 14286b7b2d80SAdrian Chadd 14296b7b2d80SAdrian Chadd static int 14306b7b2d80SAdrian Chadd nct_gpio_pin_setflags(device_t dev, uint32_t pin_num, uint32_t flags) 14316b7b2d80SAdrian Chadd { 14326b7b2d80SAdrian Chadd struct nct_softc *sc; 14336b7b2d80SAdrian Chadd struct gpio_pin *pin; 14346b7b2d80SAdrian Chadd 14357f8d2ed0SStéphane Rochoy sc = device_get_softc(dev); 14367f8d2ed0SStéphane Rochoy 14377f8d2ed0SStéphane Rochoy if (!NCT_PIN_IS_VALID(sc, pin_num)) 14386b7b2d80SAdrian Chadd return (EINVAL); 14396b7b2d80SAdrian Chadd 14406b7b2d80SAdrian Chadd pin = &sc->pins[pin_num]; 14416b7b2d80SAdrian Chadd if ((flags & pin->gp_caps) != flags) 14426b7b2d80SAdrian Chadd return (EINVAL); 14436b7b2d80SAdrian Chadd 14446b7b2d80SAdrian Chadd if ((flags & (GPIO_PIN_INPUT | GPIO_PIN_OUTPUT)) == 14456b7b2d80SAdrian Chadd (GPIO_PIN_INPUT | GPIO_PIN_OUTPUT)) { 14466b7b2d80SAdrian Chadd return (EINVAL); 14476b7b2d80SAdrian Chadd } 14486b7b2d80SAdrian Chadd if ((flags & (GPIO_PIN_OPENDRAIN | GPIO_PIN_PUSHPULL)) == 14496b7b2d80SAdrian Chadd (GPIO_PIN_OPENDRAIN | GPIO_PIN_PUSHPULL)) { 1450155514eaSAndriy Gapon return (EINVAL); 1451155514eaSAndriy Gapon } 1452155514eaSAndriy Gapon if ((flags & (GPIO_PIN_INVIN | GPIO_PIN_INVOUT)) == 1453155514eaSAndriy Gapon (GPIO_PIN_INVIN | GPIO_PIN_INVOUT)) { 14546b7b2d80SAdrian Chadd return (EINVAL); 14556b7b2d80SAdrian Chadd } 14566b7b2d80SAdrian Chadd 1457155514eaSAndriy Gapon GPIO_ASSERT_UNLOCKED(sc); 1458155514eaSAndriy Gapon GPIO_LOCK(sc); 14597f8d2ed0SStéphane Rochoy 14607f8d2ed0SStéphane Rochoy /* input or output */ 1461155514eaSAndriy Gapon if ((flags & (GPIO_PIN_INPUT | GPIO_PIN_OUTPUT)) != 0) { 1462155514eaSAndriy Gapon nct_set_pin_input(sc, pin_num, (flags & GPIO_PIN_INPUT) != 0); 1463155514eaSAndriy Gapon pin->gp_flags &= ~(GPIO_PIN_INPUT | GPIO_PIN_OUTPUT); 1464155514eaSAndriy Gapon pin->gp_flags |= flags & (GPIO_PIN_INPUT | GPIO_PIN_OUTPUT); 1465155514eaSAndriy Gapon } 14667f8d2ed0SStéphane Rochoy 14677f8d2ed0SStéphane Rochoy /* invert */ 1468155514eaSAndriy Gapon if ((flags & (GPIO_PIN_INVIN | GPIO_PIN_INVOUT)) != 0) { 14697f8d2ed0SStéphane Rochoy nct_set_pin_inverted(sc, pin_num, 1); 14707f8d2ed0SStéphane Rochoy pin->gp_flags |= (GPIO_PIN_INVIN | GPIO_PIN_INVOUT); 14717f8d2ed0SStéphane Rochoy } else { 14727f8d2ed0SStéphane Rochoy nct_set_pin_inverted(sc, pin_num, 0); 1473155514eaSAndriy Gapon pin->gp_flags &= ~(GPIO_PIN_INVIN | GPIO_PIN_INVOUT); 1474155514eaSAndriy Gapon } 14757f8d2ed0SStéphane Rochoy 14767f8d2ed0SStéphane Rochoy /* Open drain or push pull */ 1477155514eaSAndriy Gapon if ((flags & (GPIO_PIN_OPENDRAIN | GPIO_PIN_PUSHPULL)) != 0) { 14786b7b2d80SAdrian Chadd if (flags & GPIO_PIN_OPENDRAIN) 14796b7b2d80SAdrian Chadd nct_set_pin_opendrain(sc, pin_num); 14806b7b2d80SAdrian Chadd else 14816b7b2d80SAdrian Chadd nct_set_pin_pushpull(sc, pin_num); 1482155514eaSAndriy Gapon pin->gp_flags &= ~(GPIO_PIN_OPENDRAIN | GPIO_PIN_PUSHPULL); 1483155514eaSAndriy Gapon pin->gp_flags |= 1484155514eaSAndriy Gapon flags & (GPIO_PIN_OPENDRAIN | GPIO_PIN_PUSHPULL); 14856b7b2d80SAdrian Chadd } 14866b7b2d80SAdrian Chadd GPIO_UNLOCK(sc); 14876b7b2d80SAdrian Chadd 14886b7b2d80SAdrian Chadd return (0); 14896b7b2d80SAdrian Chadd } 14906b7b2d80SAdrian Chadd 14916b7b2d80SAdrian Chadd static device_method_t nct_methods[] = { 14926b7b2d80SAdrian Chadd /* Device interface */ 14936b7b2d80SAdrian Chadd DEVMETHOD(device_probe, nct_probe), 14946b7b2d80SAdrian Chadd DEVMETHOD(device_attach, nct_attach), 14956b7b2d80SAdrian Chadd DEVMETHOD(device_detach, nct_detach), 14966b7b2d80SAdrian Chadd 14976b7b2d80SAdrian Chadd /* GPIO */ 14986b7b2d80SAdrian Chadd DEVMETHOD(gpio_get_bus, nct_gpio_get_bus), 14996b7b2d80SAdrian Chadd DEVMETHOD(gpio_pin_max, nct_gpio_pin_max), 15006b7b2d80SAdrian Chadd DEVMETHOD(gpio_pin_get, nct_gpio_pin_get), 15016b7b2d80SAdrian Chadd DEVMETHOD(gpio_pin_set, nct_gpio_pin_set), 15026b7b2d80SAdrian Chadd DEVMETHOD(gpio_pin_toggle, nct_gpio_pin_toggle), 15036b7b2d80SAdrian Chadd DEVMETHOD(gpio_pin_getname, nct_gpio_pin_getname), 15046b7b2d80SAdrian Chadd DEVMETHOD(gpio_pin_getcaps, nct_gpio_pin_getcaps), 15056b7b2d80SAdrian Chadd DEVMETHOD(gpio_pin_getflags, nct_gpio_pin_getflags), 15066b7b2d80SAdrian Chadd DEVMETHOD(gpio_pin_setflags, nct_gpio_pin_setflags), 15076b7b2d80SAdrian Chadd 15086b7b2d80SAdrian Chadd DEVMETHOD_END 15096b7b2d80SAdrian Chadd }; 15106b7b2d80SAdrian Chadd 1511e3df342aSAndriy Gapon static driver_t nct_driver = { 15126b7b2d80SAdrian Chadd "gpio", 15136b7b2d80SAdrian Chadd nct_methods, 15146b7b2d80SAdrian Chadd sizeof(struct nct_softc) 15156b7b2d80SAdrian Chadd }; 15166b7b2d80SAdrian Chadd 151784c5f982SJohn Baldwin DRIVER_MODULE(nctgpio, superio, nct_driver, NULL, NULL); 15186b7b2d80SAdrian Chadd MODULE_DEPEND(nctgpio, gpiobus, 1, 1, 1); 1519e3df342aSAndriy Gapon MODULE_DEPEND(nctgpio, superio, 1, 1, 1); 1520e3df342aSAndriy Gapon MODULE_VERSION(nctgpio, 1); 1521