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 356b7b2d80SAdrian Chadd #include <sys/cdefs.h> 366b7b2d80SAdrian Chadd 376b7b2d80SAdrian Chadd #include <sys/param.h> 386b7b2d80SAdrian Chadd #include <sys/kernel.h> 396b7b2d80SAdrian Chadd #include <sys/systm.h> 406b7b2d80SAdrian Chadd #include <sys/bus.h> 416b7b2d80SAdrian Chadd #include <sys/eventhandler.h> 426b7b2d80SAdrian Chadd #include <sys/lock.h> 436b7b2d80SAdrian Chadd 446b7b2d80SAdrian Chadd #include <sys/module.h> 456b7b2d80SAdrian Chadd #include <sys/rman.h> 466b7b2d80SAdrian Chadd #include <sys/gpio.h> 476b7b2d80SAdrian Chadd 486b7b2d80SAdrian Chadd #include <isa/isavar.h> 496b7b2d80SAdrian Chadd 506b7b2d80SAdrian Chadd #include <machine/bus.h> 516b7b2d80SAdrian Chadd #include <machine/resource.h> 526b7b2d80SAdrian Chadd 536b7b2d80SAdrian Chadd #include <dev/gpio/gpiobusvar.h> 546b7b2d80SAdrian Chadd 556b7b2d80SAdrian Chadd #include "gpio_if.h" 566b7b2d80SAdrian Chadd 576b7b2d80SAdrian Chadd /* 586b7b2d80SAdrian Chadd * Global configuration registers (CR). 596b7b2d80SAdrian Chadd */ 606b7b2d80SAdrian Chadd #define NCT_CR_LDN 0x07 /* Logical Device Number */ 616b7b2d80SAdrian Chadd #define NCT_CR_CHIP_ID 0x20 /* Chip ID */ 626b7b2d80SAdrian Chadd #define NCT_CR_CHIP_ID_H 0x20 /* Chip ID (high byte) */ 636b7b2d80SAdrian Chadd #define NCT_CR_CHIP_ID_L 0x21 /* Chip ID (low byte) */ 646b7b2d80SAdrian Chadd #define NCT_CR_OPT_1 0x26 /* Global Options (1) */ 656b7b2d80SAdrian Chadd 666b7b2d80SAdrian Chadd /* Logical Device Numbers. */ 676b7b2d80SAdrian Chadd #define NCT_LDN_GPIO 0x07 686b7b2d80SAdrian Chadd #define NCT_LDN_GPIO_CFG 0x08 696b7b2d80SAdrian Chadd #define NCT_LDN_GPIO_MODE 0x0f 706b7b2d80SAdrian Chadd 716b7b2d80SAdrian Chadd /* Logical Device 7 */ 726b7b2d80SAdrian Chadd #define NCT_LD7_GPIO_ENABLE 0x30 736b7b2d80SAdrian Chadd #define NCT_LD7_GPIO0_IOR 0xe0 746b7b2d80SAdrian Chadd #define NCT_LD7_GPIO0_DAT 0xe1 756b7b2d80SAdrian Chadd #define NCT_LD7_GPIO0_INV 0xe2 766b7b2d80SAdrian Chadd #define NCT_LD7_GPIO0_DST 0xe3 776b7b2d80SAdrian Chadd #define NCT_LD7_GPIO1_IOR 0xe4 786b7b2d80SAdrian Chadd #define NCT_LD7_GPIO1_DAT 0xe5 796b7b2d80SAdrian Chadd #define NCT_LD7_GPIO1_INV 0xe6 806b7b2d80SAdrian Chadd #define NCT_LD7_GPIO1_DST 0xe7 816b7b2d80SAdrian Chadd 826b7b2d80SAdrian Chadd /* Logical Device F */ 836b7b2d80SAdrian Chadd #define NCT_LDF_GPIO0_OUTCFG 0xe0 846b7b2d80SAdrian Chadd #define NCT_LDF_GPIO1_OUTCFG 0xe1 856b7b2d80SAdrian Chadd 866b7b2d80SAdrian Chadd #define NCT_EXTFUNC_ENTER 0x87 876b7b2d80SAdrian Chadd #define NCT_EXTFUNC_EXIT 0xaa 886b7b2d80SAdrian Chadd 896b7b2d80SAdrian Chadd #define NCT_MAX_PIN 15 906b7b2d80SAdrian Chadd #define NCT_IS_VALID_PIN(_p) ((_p) >= 0 && (_p) <= NCT_MAX_PIN) 916b7b2d80SAdrian Chadd 926b7b2d80SAdrian Chadd #define NCT_PIN_BIT(_p) (1 << ((_p) % 8)) 936b7b2d80SAdrian Chadd 946b7b2d80SAdrian Chadd #define NCT_GPIO_CAPS (GPIO_PIN_INPUT | GPIO_PIN_OUTPUT | \ 956b7b2d80SAdrian Chadd GPIO_PIN_OPENDRAIN | GPIO_PIN_PUSHPULL | \ 966b7b2d80SAdrian Chadd GPIO_PIN_INVIN | GPIO_PIN_INVOUT) 976b7b2d80SAdrian Chadd 986b7b2d80SAdrian Chadd struct nct_softc { 996b7b2d80SAdrian Chadd device_t dev; 1006b7b2d80SAdrian Chadd device_t busdev; 1016b7b2d80SAdrian Chadd struct mtx mtx; 1026b7b2d80SAdrian Chadd struct resource *portres; 1036b7b2d80SAdrian Chadd int rid; 104523af57eSConrad Meyer struct gpio_pin pins[NCT_MAX_PIN + 1]; 1056b7b2d80SAdrian Chadd }; 1066b7b2d80SAdrian Chadd 1076b7b2d80SAdrian Chadd #define GPIO_LOCK_INIT(_sc) mtx_init(&(_sc)->mtx, \ 1086b7b2d80SAdrian Chadd device_get_nameunit(dev), NULL, MTX_DEF) 1096b7b2d80SAdrian Chadd #define GPIO_LOCK_DESTROY(_sc) mtx_destroy(&(_sc)->mtx) 1106b7b2d80SAdrian Chadd #define GPIO_LOCK(_sc) mtx_lock(&(_sc)->mtx) 1116b7b2d80SAdrian Chadd #define GPIO_UNLOCK(_sc) mtx_unlock(&(_sc)->mtx) 1126b7b2d80SAdrian Chadd #define GPIO_ASSERT_LOCKED(_sc) mtx_assert(&(_sc)->mtx, MA_OWNED) 1136b7b2d80SAdrian Chadd #define GPIO_ASSERT_UNLOCKED(_sc) mtx_assert(&(_sc)->mtx, MA_NOTOWNED) 1146b7b2d80SAdrian Chadd 1156b7b2d80SAdrian Chadd #define NCT_BARRIER_WRITE(_sc) \ 1166b7b2d80SAdrian Chadd bus_barrier((_sc)->portres, 0, 2, BUS_SPACE_BARRIER_WRITE) 1176b7b2d80SAdrian Chadd 1186b7b2d80SAdrian Chadd #define NCT_BARRIER_READ_WRITE(_sc) \ 1196b7b2d80SAdrian Chadd bus_barrier((_sc)->portres, 0, 2, \ 1206b7b2d80SAdrian Chadd BUS_SPACE_BARRIER_READ | BUS_SPACE_BARRIER_WRITE) 1216b7b2d80SAdrian Chadd 1226b7b2d80SAdrian Chadd static void ext_cfg_enter(struct nct_softc *); 1236b7b2d80SAdrian Chadd static void ext_cfg_exit(struct nct_softc *); 1246b7b2d80SAdrian Chadd 1256b7b2d80SAdrian Chadd /* 1266b7b2d80SAdrian Chadd * Potential Extended Function Enable Register addresses. 1276b7b2d80SAdrian Chadd * Same address as EFIR. 1286b7b2d80SAdrian Chadd */ 1296b7b2d80SAdrian Chadd uint8_t probe_addrs[] = {0x2e, 0x4e}; 1306b7b2d80SAdrian Chadd 1316b7b2d80SAdrian Chadd struct nuvoton_vendor_device_id { 1326b7b2d80SAdrian Chadd uint16_t chip_id; 1336b7b2d80SAdrian Chadd const char * descr; 1346b7b2d80SAdrian Chadd } nct_devs[] = { 1356b7b2d80SAdrian Chadd { 1366b7b2d80SAdrian Chadd .chip_id = 0x1061, 1376b7b2d80SAdrian Chadd .descr = "Nuvoton NCT5104D", 1386b7b2d80SAdrian Chadd }, 1396b7b2d80SAdrian Chadd { 1406b7b2d80SAdrian Chadd .chip_id = 0xc452, 1416b7b2d80SAdrian Chadd .descr = "Nuvoton NCT5104D (PC-Engines APU)", 1426b7b2d80SAdrian Chadd }, 143*9d1208bbSOleksandr Tymoshenko { 144*9d1208bbSOleksandr Tymoshenko .chip_id = 0xc453, 145*9d1208bbSOleksandr Tymoshenko .descr = "Nuvoton NCT5104D (PC-Engines APU3)", 146*9d1208bbSOleksandr Tymoshenko }, 1476b7b2d80SAdrian Chadd }; 1486b7b2d80SAdrian Chadd 1496b7b2d80SAdrian Chadd static void 1506b7b2d80SAdrian Chadd write_cfg_reg_1(struct nct_softc *sc, uint8_t reg, uint8_t value) 1516b7b2d80SAdrian Chadd { 1526b7b2d80SAdrian Chadd GPIO_ASSERT_LOCKED(sc); 1536b7b2d80SAdrian Chadd bus_write_1(sc->portres, 0, reg); 1546b7b2d80SAdrian Chadd NCT_BARRIER_WRITE(sc); 1556b7b2d80SAdrian Chadd bus_write_1(sc->portres, 1, value); 1566b7b2d80SAdrian Chadd NCT_BARRIER_WRITE(sc); 1576b7b2d80SAdrian Chadd } 1586b7b2d80SAdrian Chadd 1596b7b2d80SAdrian Chadd static uint8_t 1606b7b2d80SAdrian Chadd read_cfg_reg_1(struct nct_softc *sc, uint8_t reg) 1616b7b2d80SAdrian Chadd { 1626b7b2d80SAdrian Chadd uint8_t value; 1636b7b2d80SAdrian Chadd 1646b7b2d80SAdrian Chadd GPIO_ASSERT_LOCKED(sc); 1656b7b2d80SAdrian Chadd bus_write_1(sc->portres, 0, reg); 1666b7b2d80SAdrian Chadd NCT_BARRIER_READ_WRITE(sc); 1676b7b2d80SAdrian Chadd value = bus_read_1(sc->portres, 1); 1686b7b2d80SAdrian Chadd NCT_BARRIER_READ_WRITE(sc); 1696b7b2d80SAdrian Chadd 1706b7b2d80SAdrian Chadd return (value); 1716b7b2d80SAdrian Chadd } 1726b7b2d80SAdrian Chadd 1736b7b2d80SAdrian Chadd static uint16_t 1746b7b2d80SAdrian Chadd read_cfg_reg_2(struct nct_softc *sc, uint8_t reg) 1756b7b2d80SAdrian Chadd { 1766b7b2d80SAdrian Chadd uint16_t value; 1776b7b2d80SAdrian Chadd 1786b7b2d80SAdrian Chadd value = read_cfg_reg_1(sc, reg) << 8; 1796b7b2d80SAdrian Chadd value |= read_cfg_reg_1(sc, reg + 1); 1806b7b2d80SAdrian Chadd 1816b7b2d80SAdrian Chadd return (value); 1826b7b2d80SAdrian Chadd } 1836b7b2d80SAdrian Chadd 1846b7b2d80SAdrian Chadd /* 1856b7b2d80SAdrian Chadd * Enable extended function mode. 1866b7b2d80SAdrian Chadd * 1876b7b2d80SAdrian Chadd */ 1886b7b2d80SAdrian Chadd static void 1896b7b2d80SAdrian Chadd ext_cfg_enter(struct nct_softc *sc) 1906b7b2d80SAdrian Chadd { 1916b7b2d80SAdrian Chadd GPIO_ASSERT_LOCKED(sc); 1926b7b2d80SAdrian Chadd bus_write_1(sc->portres, 0, NCT_EXTFUNC_ENTER); 1936b7b2d80SAdrian Chadd NCT_BARRIER_WRITE(sc); 1946b7b2d80SAdrian Chadd bus_write_1(sc->portres, 0, NCT_EXTFUNC_ENTER); 1956b7b2d80SAdrian Chadd NCT_BARRIER_WRITE(sc); 1966b7b2d80SAdrian Chadd } 1976b7b2d80SAdrian Chadd 1986b7b2d80SAdrian Chadd /* 1996b7b2d80SAdrian Chadd * Disable extended function mode. 2006b7b2d80SAdrian Chadd * 2016b7b2d80SAdrian Chadd */ 2026b7b2d80SAdrian Chadd static void 2036b7b2d80SAdrian Chadd ext_cfg_exit(struct nct_softc *sc) 2046b7b2d80SAdrian Chadd { 2056b7b2d80SAdrian Chadd GPIO_ASSERT_LOCKED(sc); 2066b7b2d80SAdrian Chadd bus_write_1(sc->portres, 0, NCT_EXTFUNC_EXIT); 2076b7b2d80SAdrian Chadd NCT_BARRIER_WRITE(sc); 2086b7b2d80SAdrian Chadd } 2096b7b2d80SAdrian Chadd 2106b7b2d80SAdrian Chadd /* 2116b7b2d80SAdrian Chadd * Select a Logical Device. 2126b7b2d80SAdrian Chadd */ 2136b7b2d80SAdrian Chadd static void 2146b7b2d80SAdrian Chadd select_ldn(struct nct_softc *sc, uint8_t ldn) 2156b7b2d80SAdrian Chadd { 2166b7b2d80SAdrian Chadd write_cfg_reg_1(sc, NCT_CR_LDN, ldn); 2176b7b2d80SAdrian Chadd } 2186b7b2d80SAdrian Chadd 2196b7b2d80SAdrian Chadd /* 2206b7b2d80SAdrian Chadd * Get the GPIO Input/Output register address 2216b7b2d80SAdrian Chadd * for a pin. 2226b7b2d80SAdrian Chadd */ 2236b7b2d80SAdrian Chadd static uint8_t 2246b7b2d80SAdrian Chadd nct_ior_addr(uint32_t pin_num) 2256b7b2d80SAdrian Chadd { 2266b7b2d80SAdrian Chadd uint8_t addr; 2276b7b2d80SAdrian Chadd 2286b7b2d80SAdrian Chadd addr = NCT_LD7_GPIO0_IOR; 2296b7b2d80SAdrian Chadd if (pin_num > 7) 2306b7b2d80SAdrian Chadd addr = NCT_LD7_GPIO1_IOR; 2316b7b2d80SAdrian Chadd 2326b7b2d80SAdrian Chadd return (addr); 2336b7b2d80SAdrian Chadd } 2346b7b2d80SAdrian Chadd 2356b7b2d80SAdrian Chadd /* 2366b7b2d80SAdrian Chadd * Get the GPIO Data register address for a pin. 2376b7b2d80SAdrian Chadd */ 2386b7b2d80SAdrian Chadd static uint8_t 2396b7b2d80SAdrian Chadd nct_dat_addr(uint32_t pin_num) 2406b7b2d80SAdrian Chadd { 2416b7b2d80SAdrian Chadd uint8_t addr; 2426b7b2d80SAdrian Chadd 2436b7b2d80SAdrian Chadd addr = NCT_LD7_GPIO0_DAT; 2446b7b2d80SAdrian Chadd if (pin_num > 7) 2456b7b2d80SAdrian Chadd addr = NCT_LD7_GPIO1_DAT; 2466b7b2d80SAdrian Chadd 2476b7b2d80SAdrian Chadd return (addr); 2486b7b2d80SAdrian Chadd } 2496b7b2d80SAdrian Chadd 2506b7b2d80SAdrian Chadd /* 2516b7b2d80SAdrian Chadd * Get the GPIO Inversion register address 2526b7b2d80SAdrian Chadd * for a pin. 2536b7b2d80SAdrian Chadd */ 2546b7b2d80SAdrian Chadd static uint8_t 2556b7b2d80SAdrian Chadd nct_inv_addr(uint32_t pin_num) 2566b7b2d80SAdrian Chadd { 2576b7b2d80SAdrian Chadd uint8_t addr; 2586b7b2d80SAdrian Chadd 2596b7b2d80SAdrian Chadd addr = NCT_LD7_GPIO0_INV; 2606b7b2d80SAdrian Chadd if (pin_num > 7) 2616b7b2d80SAdrian Chadd addr = NCT_LD7_GPIO1_INV; 2626b7b2d80SAdrian Chadd 2636b7b2d80SAdrian Chadd return (addr); 2646b7b2d80SAdrian Chadd } 2656b7b2d80SAdrian Chadd 2666b7b2d80SAdrian Chadd /* 2676b7b2d80SAdrian Chadd * Get the GPIO Output Configuration/Mode 2686b7b2d80SAdrian Chadd * register address for a pin. 2696b7b2d80SAdrian Chadd */ 2706b7b2d80SAdrian Chadd static uint8_t 2716b7b2d80SAdrian Chadd nct_outcfg_addr(uint32_t pin_num) 2726b7b2d80SAdrian Chadd { 2736b7b2d80SAdrian Chadd uint8_t addr; 2746b7b2d80SAdrian Chadd 2756b7b2d80SAdrian Chadd addr = NCT_LDF_GPIO0_OUTCFG; 2766b7b2d80SAdrian Chadd if (pin_num > 7) 2776b7b2d80SAdrian Chadd addr = NCT_LDF_GPIO1_OUTCFG; 2786b7b2d80SAdrian Chadd 2796b7b2d80SAdrian Chadd return (addr); 2806b7b2d80SAdrian Chadd } 2816b7b2d80SAdrian Chadd 2826b7b2d80SAdrian Chadd /* 2836b7b2d80SAdrian Chadd * Set a pin to output mode. 2846b7b2d80SAdrian Chadd */ 2856b7b2d80SAdrian Chadd static void 2866b7b2d80SAdrian Chadd nct_set_pin_is_output(struct nct_softc *sc, uint32_t pin_num) 2876b7b2d80SAdrian Chadd { 2886b7b2d80SAdrian Chadd uint8_t reg; 2896b7b2d80SAdrian Chadd uint8_t ior; 2906b7b2d80SAdrian Chadd 2916b7b2d80SAdrian Chadd reg = nct_ior_addr(pin_num); 2926b7b2d80SAdrian Chadd select_ldn(sc, NCT_LDN_GPIO); 2936b7b2d80SAdrian Chadd ior = read_cfg_reg_1(sc, reg); 2946b7b2d80SAdrian Chadd ior &= ~(NCT_PIN_BIT(pin_num)); 2956b7b2d80SAdrian Chadd write_cfg_reg_1(sc, reg, ior); 2966b7b2d80SAdrian Chadd } 2976b7b2d80SAdrian Chadd 2986b7b2d80SAdrian Chadd /* 2996b7b2d80SAdrian Chadd * Set a pin to input mode. 3006b7b2d80SAdrian Chadd */ 3016b7b2d80SAdrian Chadd static void 3026b7b2d80SAdrian Chadd nct_set_pin_is_input(struct nct_softc *sc, uint32_t pin_num) 3036b7b2d80SAdrian Chadd { 3046b7b2d80SAdrian Chadd uint8_t reg; 3056b7b2d80SAdrian Chadd uint8_t ior; 3066b7b2d80SAdrian Chadd 3076b7b2d80SAdrian Chadd reg = nct_ior_addr(pin_num); 3086b7b2d80SAdrian Chadd select_ldn(sc, NCT_LDN_GPIO); 3096b7b2d80SAdrian Chadd ior = read_cfg_reg_1(sc, reg); 3106b7b2d80SAdrian Chadd ior |= NCT_PIN_BIT(pin_num); 3116b7b2d80SAdrian Chadd write_cfg_reg_1(sc, reg, ior); 3126b7b2d80SAdrian Chadd } 3136b7b2d80SAdrian Chadd 3146b7b2d80SAdrian Chadd /* 3156b7b2d80SAdrian Chadd * Check whether a pin is configured as an input. 3166b7b2d80SAdrian Chadd */ 3176b7b2d80SAdrian Chadd static bool 3186b7b2d80SAdrian Chadd nct_pin_is_input(struct nct_softc *sc, uint32_t pin_num) 3196b7b2d80SAdrian Chadd { 3206b7b2d80SAdrian Chadd uint8_t reg; 3216b7b2d80SAdrian Chadd uint8_t ior; 3226b7b2d80SAdrian Chadd 3236b7b2d80SAdrian Chadd reg = nct_ior_addr(pin_num); 3246b7b2d80SAdrian Chadd select_ldn(sc, NCT_LDN_GPIO); 3256b7b2d80SAdrian Chadd ior = read_cfg_reg_1(sc, reg); 3266b7b2d80SAdrian Chadd 3276b7b2d80SAdrian Chadd return (ior & NCT_PIN_BIT(pin_num)); 3286b7b2d80SAdrian Chadd } 3296b7b2d80SAdrian Chadd 3306b7b2d80SAdrian Chadd /* 3316b7b2d80SAdrian Chadd * Write a value to an output pin. 3326b7b2d80SAdrian Chadd */ 3336b7b2d80SAdrian Chadd static void 3346b7b2d80SAdrian Chadd nct_write_pin(struct nct_softc *sc, uint32_t pin_num, uint8_t data) 3356b7b2d80SAdrian Chadd { 3366b7b2d80SAdrian Chadd uint8_t reg; 3376b7b2d80SAdrian Chadd uint8_t value; 3386b7b2d80SAdrian Chadd 3396b7b2d80SAdrian Chadd reg = nct_dat_addr(pin_num); 3406b7b2d80SAdrian Chadd select_ldn(sc, NCT_LDN_GPIO); 3416b7b2d80SAdrian Chadd value = read_cfg_reg_1(sc, reg); 3426b7b2d80SAdrian Chadd if (data) 3436b7b2d80SAdrian Chadd value |= NCT_PIN_BIT(pin_num); 3446b7b2d80SAdrian Chadd else 3456b7b2d80SAdrian Chadd value &= ~(NCT_PIN_BIT(pin_num)); 3466b7b2d80SAdrian Chadd 3476b7b2d80SAdrian Chadd write_cfg_reg_1(sc, reg, value); 3486b7b2d80SAdrian Chadd } 3496b7b2d80SAdrian Chadd 3506b7b2d80SAdrian Chadd static bool 3516b7b2d80SAdrian Chadd nct_read_pin(struct nct_softc *sc, uint32_t pin_num) 3526b7b2d80SAdrian Chadd { 3536b7b2d80SAdrian Chadd uint8_t reg; 3546b7b2d80SAdrian Chadd 3556b7b2d80SAdrian Chadd reg = nct_dat_addr(pin_num); 3566b7b2d80SAdrian Chadd select_ldn(sc, NCT_LDN_GPIO); 3576b7b2d80SAdrian Chadd 3586b7b2d80SAdrian Chadd return (read_cfg_reg_1(sc, reg) & NCT_PIN_BIT(pin_num)); 3596b7b2d80SAdrian Chadd } 3606b7b2d80SAdrian Chadd 3616b7b2d80SAdrian Chadd static void 3626b7b2d80SAdrian Chadd nct_set_pin_is_inverted(struct nct_softc *sc, uint32_t pin_num) 3636b7b2d80SAdrian Chadd { 3646b7b2d80SAdrian Chadd uint8_t reg; 3656b7b2d80SAdrian Chadd uint8_t inv; 3666b7b2d80SAdrian Chadd 3676b7b2d80SAdrian Chadd reg = nct_inv_addr(pin_num); 3686b7b2d80SAdrian Chadd select_ldn(sc, NCT_LDN_GPIO); 3696b7b2d80SAdrian Chadd inv = read_cfg_reg_1(sc, reg); 3706b7b2d80SAdrian Chadd inv |= (NCT_PIN_BIT(pin_num)); 3716b7b2d80SAdrian Chadd write_cfg_reg_1(sc, reg, inv); 3726b7b2d80SAdrian Chadd } 3736b7b2d80SAdrian Chadd 3746b7b2d80SAdrian Chadd static void 3756b7b2d80SAdrian Chadd nct_set_pin_not_inverted(struct nct_softc *sc, uint32_t pin_num) 3766b7b2d80SAdrian Chadd { 3776b7b2d80SAdrian Chadd uint8_t reg; 3786b7b2d80SAdrian Chadd uint8_t inv; 3796b7b2d80SAdrian Chadd 3806b7b2d80SAdrian Chadd reg = nct_inv_addr(pin_num); 3816b7b2d80SAdrian Chadd select_ldn(sc, NCT_LDN_GPIO); 3826b7b2d80SAdrian Chadd inv = read_cfg_reg_1(sc, reg); 3836b7b2d80SAdrian Chadd inv &= ~(NCT_PIN_BIT(pin_num)); 3846b7b2d80SAdrian Chadd write_cfg_reg_1(sc, reg, inv); 3856b7b2d80SAdrian Chadd } 3866b7b2d80SAdrian Chadd 3876b7b2d80SAdrian Chadd static bool 3886b7b2d80SAdrian Chadd nct_pin_is_inverted(struct nct_softc *sc, uint32_t pin_num) 3896b7b2d80SAdrian Chadd { 3906b7b2d80SAdrian Chadd uint8_t reg; 3916b7b2d80SAdrian Chadd uint8_t inv; 3926b7b2d80SAdrian Chadd 3936b7b2d80SAdrian Chadd reg = nct_inv_addr(pin_num); 3946b7b2d80SAdrian Chadd select_ldn(sc, NCT_LDN_GPIO); 3956b7b2d80SAdrian Chadd inv = read_cfg_reg_1(sc, reg); 3966b7b2d80SAdrian Chadd 3976b7b2d80SAdrian Chadd return (inv & NCT_PIN_BIT(pin_num)); 3986b7b2d80SAdrian Chadd } 3996b7b2d80SAdrian Chadd 4006b7b2d80SAdrian Chadd static void 4016b7b2d80SAdrian Chadd nct_set_pin_opendrain(struct nct_softc *sc, uint32_t pin_num) 4026b7b2d80SAdrian Chadd { 4036b7b2d80SAdrian Chadd uint8_t reg; 4046b7b2d80SAdrian Chadd uint8_t outcfg; 4056b7b2d80SAdrian Chadd 4066b7b2d80SAdrian Chadd reg = nct_outcfg_addr(pin_num); 4076b7b2d80SAdrian Chadd select_ldn(sc, NCT_LDN_GPIO_MODE); 4086b7b2d80SAdrian Chadd outcfg = read_cfg_reg_1(sc, reg); 4096b7b2d80SAdrian Chadd outcfg |= (NCT_PIN_BIT(pin_num)); 4106b7b2d80SAdrian Chadd write_cfg_reg_1(sc, reg, outcfg); 4116b7b2d80SAdrian Chadd } 4126b7b2d80SAdrian Chadd 4136b7b2d80SAdrian Chadd static void 4146b7b2d80SAdrian Chadd nct_set_pin_pushpull(struct nct_softc *sc, uint32_t pin_num) 4156b7b2d80SAdrian Chadd { 4166b7b2d80SAdrian Chadd uint8_t reg; 4176b7b2d80SAdrian Chadd uint8_t outcfg; 4186b7b2d80SAdrian Chadd 4196b7b2d80SAdrian Chadd reg = nct_outcfg_addr(pin_num); 4206b7b2d80SAdrian Chadd select_ldn(sc, NCT_LDN_GPIO_MODE); 4216b7b2d80SAdrian Chadd outcfg = read_cfg_reg_1(sc, reg); 4226b7b2d80SAdrian Chadd outcfg &= ~(NCT_PIN_BIT(pin_num)); 4236b7b2d80SAdrian Chadd write_cfg_reg_1(sc, reg, outcfg); 4246b7b2d80SAdrian Chadd } 4256b7b2d80SAdrian Chadd 4266b7b2d80SAdrian Chadd static bool 4276b7b2d80SAdrian Chadd nct_pin_is_opendrain(struct nct_softc *sc, uint32_t pin_num) 4286b7b2d80SAdrian Chadd { 4296b7b2d80SAdrian Chadd uint8_t reg; 4306b7b2d80SAdrian Chadd uint8_t outcfg; 4316b7b2d80SAdrian Chadd 4326b7b2d80SAdrian Chadd reg = nct_outcfg_addr(pin_num); 4336b7b2d80SAdrian Chadd select_ldn(sc, NCT_LDN_GPIO_MODE); 4346b7b2d80SAdrian Chadd outcfg = read_cfg_reg_1(sc, reg); 4356b7b2d80SAdrian Chadd 4366b7b2d80SAdrian Chadd return (outcfg & NCT_PIN_BIT(pin_num)); 4376b7b2d80SAdrian Chadd } 4386b7b2d80SAdrian Chadd 4396b7b2d80SAdrian Chadd static void 4406b7b2d80SAdrian Chadd nct_identify(driver_t *driver, device_t parent) 4416b7b2d80SAdrian Chadd { 4426b7b2d80SAdrian Chadd if (device_find_child(parent, driver->name, 0) != NULL) 4436b7b2d80SAdrian Chadd return; 4446b7b2d80SAdrian Chadd 4456b7b2d80SAdrian Chadd BUS_ADD_CHILD(parent, 0, driver->name, 0); 4466b7b2d80SAdrian Chadd } 4476b7b2d80SAdrian Chadd 4486b7b2d80SAdrian Chadd static int 4496b7b2d80SAdrian Chadd nct_probe(device_t dev) 4506b7b2d80SAdrian Chadd { 4516b7b2d80SAdrian Chadd int i, j; 4526b7b2d80SAdrian Chadd int rc; 4536b7b2d80SAdrian Chadd struct nct_softc *sc; 4546b7b2d80SAdrian Chadd uint16_t chipid; 4556b7b2d80SAdrian Chadd 4566b7b2d80SAdrian Chadd /* Make sure we do not claim some ISA PNP device. */ 4576b7b2d80SAdrian Chadd if (isa_get_logicalid(dev) != 0) 4586b7b2d80SAdrian Chadd return (ENXIO); 4596b7b2d80SAdrian Chadd 4606b7b2d80SAdrian Chadd sc = device_get_softc(dev); 4616b7b2d80SAdrian Chadd 46273a1170aSPedro F. Giffuni for (i = 0; i < nitems(probe_addrs); i++) { 4636b7b2d80SAdrian Chadd sc->rid = 0; 4646b7b2d80SAdrian Chadd sc->portres = bus_alloc_resource(dev, SYS_RES_IOPORT, &sc->rid, 4656b7b2d80SAdrian Chadd probe_addrs[i], probe_addrs[i] + 1, 2, RF_ACTIVE); 4666b7b2d80SAdrian Chadd if (sc->portres == NULL) 4676b7b2d80SAdrian Chadd continue; 4686b7b2d80SAdrian Chadd 4696b7b2d80SAdrian Chadd GPIO_LOCK_INIT(sc); 4706b7b2d80SAdrian Chadd 4716b7b2d80SAdrian Chadd GPIO_ASSERT_UNLOCKED(sc); 4726b7b2d80SAdrian Chadd GPIO_LOCK(sc); 4736b7b2d80SAdrian Chadd ext_cfg_enter(sc); 4746b7b2d80SAdrian Chadd chipid = read_cfg_reg_2(sc, NCT_CR_CHIP_ID); 4756b7b2d80SAdrian Chadd ext_cfg_exit(sc); 4766b7b2d80SAdrian Chadd GPIO_UNLOCK(sc); 4776b7b2d80SAdrian Chadd 4786b7b2d80SAdrian Chadd GPIO_LOCK_DESTROY(sc); 4796b7b2d80SAdrian Chadd 4806b7b2d80SAdrian Chadd bus_release_resource(dev, SYS_RES_IOPORT, sc->rid, sc->portres); 4816b7b2d80SAdrian Chadd bus_delete_resource(dev, SYS_RES_IOPORT, sc->rid); 4826b7b2d80SAdrian Chadd 48373a1170aSPedro F. Giffuni for (j = 0; j < nitems(nct_devs); j++) { 4846b7b2d80SAdrian Chadd if (chipid == nct_devs[j].chip_id) { 4856b7b2d80SAdrian Chadd rc = bus_set_resource(dev, SYS_RES_IOPORT, 0, probe_addrs[i], 2); 4866b7b2d80SAdrian Chadd if (rc != 0) { 4876b7b2d80SAdrian Chadd device_printf(dev, "bus_set_resource failed for address 0x%02X\n", probe_addrs[i]); 4886b7b2d80SAdrian Chadd continue; 4896b7b2d80SAdrian Chadd } 4906b7b2d80SAdrian Chadd device_set_desc(dev, nct_devs[j].descr); 4916b7b2d80SAdrian Chadd return (BUS_PROBE_DEFAULT); 4926b7b2d80SAdrian Chadd } 4936b7b2d80SAdrian Chadd } 4946b7b2d80SAdrian Chadd } 4956b7b2d80SAdrian Chadd return (ENXIO); 4966b7b2d80SAdrian Chadd } 4976b7b2d80SAdrian Chadd 4986b7b2d80SAdrian Chadd static int 4996b7b2d80SAdrian Chadd nct_attach(device_t dev) 5006b7b2d80SAdrian Chadd { 5016b7b2d80SAdrian Chadd struct nct_softc *sc; 5026b7b2d80SAdrian Chadd int i; 5036b7b2d80SAdrian Chadd 5046b7b2d80SAdrian Chadd sc = device_get_softc(dev); 5056b7b2d80SAdrian Chadd 5066b7b2d80SAdrian Chadd sc->rid = 0; 5076b7b2d80SAdrian Chadd sc->portres = bus_alloc_resource(dev, SYS_RES_IOPORT, &sc->rid, 5086b7b2d80SAdrian Chadd 0ul, ~0ul, 2, RF_ACTIVE); 5096b7b2d80SAdrian Chadd if (sc->portres == NULL) { 5106b7b2d80SAdrian Chadd device_printf(dev, "cannot allocate ioport\n"); 5116b7b2d80SAdrian Chadd return (ENXIO); 5126b7b2d80SAdrian Chadd } 5136b7b2d80SAdrian Chadd 5146b7b2d80SAdrian Chadd GPIO_LOCK_INIT(sc); 5156b7b2d80SAdrian Chadd 5166b7b2d80SAdrian Chadd GPIO_ASSERT_UNLOCKED(sc); 5176b7b2d80SAdrian Chadd GPIO_LOCK(sc); 5186b7b2d80SAdrian Chadd ext_cfg_enter(sc); 5196b7b2d80SAdrian Chadd select_ldn(sc, NCT_LDN_GPIO); 5206b7b2d80SAdrian Chadd /* Enable gpio0 and gpio1. */ 5216b7b2d80SAdrian Chadd write_cfg_reg_1(sc, NCT_LD7_GPIO_ENABLE, 5226b7b2d80SAdrian Chadd read_cfg_reg_1(sc, NCT_LD7_GPIO_ENABLE) | 0x03); 5236b7b2d80SAdrian Chadd 5246b7b2d80SAdrian Chadd for (i = 0; i <= NCT_MAX_PIN; i++) { 5256b7b2d80SAdrian Chadd struct gpio_pin *pin; 5266b7b2d80SAdrian Chadd 5276b7b2d80SAdrian Chadd pin = &sc->pins[i]; 5286b7b2d80SAdrian Chadd pin->gp_pin = i; 5296b7b2d80SAdrian Chadd pin->gp_caps = NCT_GPIO_CAPS; 5306b7b2d80SAdrian Chadd pin->gp_flags = 0; 5316b7b2d80SAdrian Chadd 5326b7b2d80SAdrian Chadd snprintf(pin->gp_name, GPIOMAXNAME, "GPIO%02u", i); 5336b7b2d80SAdrian Chadd pin->gp_name[GPIOMAXNAME - 1] = '\0'; 5346b7b2d80SAdrian Chadd 5356b7b2d80SAdrian Chadd if (nct_pin_is_input(sc, i)) 5366b7b2d80SAdrian Chadd pin->gp_flags |= GPIO_PIN_INPUT; 5376b7b2d80SAdrian Chadd else 5386b7b2d80SAdrian Chadd pin->gp_flags |= GPIO_PIN_OUTPUT; 5396b7b2d80SAdrian Chadd 5406b7b2d80SAdrian Chadd if (nct_pin_is_opendrain(sc, i)) 5416b7b2d80SAdrian Chadd pin->gp_flags |= GPIO_PIN_OPENDRAIN; 5426b7b2d80SAdrian Chadd else 5436b7b2d80SAdrian Chadd pin->gp_flags |= GPIO_PIN_PUSHPULL; 5446b7b2d80SAdrian Chadd 5456b7b2d80SAdrian Chadd if (nct_pin_is_inverted(sc, i)) 5466b7b2d80SAdrian Chadd pin->gp_flags |= (GPIO_PIN_INVIN | GPIO_PIN_INVOUT); 5476b7b2d80SAdrian Chadd } 5486b7b2d80SAdrian Chadd GPIO_UNLOCK(sc); 5496b7b2d80SAdrian Chadd 5506b7b2d80SAdrian Chadd sc->busdev = gpiobus_attach_bus(dev); 5516b7b2d80SAdrian Chadd if (sc->busdev == NULL) { 5526b7b2d80SAdrian Chadd GPIO_ASSERT_UNLOCKED(sc); 5536b7b2d80SAdrian Chadd GPIO_LOCK(sc); 5546b7b2d80SAdrian Chadd ext_cfg_exit(sc); 5556b7b2d80SAdrian Chadd GPIO_UNLOCK(sc); 5566b7b2d80SAdrian Chadd bus_release_resource(dev, SYS_RES_IOPORT, sc->rid, sc->portres); 5576b7b2d80SAdrian Chadd GPIO_LOCK_DESTROY(sc); 5586b7b2d80SAdrian Chadd 5596b7b2d80SAdrian Chadd return (ENXIO); 5606b7b2d80SAdrian Chadd } 5616b7b2d80SAdrian Chadd 5626b7b2d80SAdrian Chadd return (0); 5636b7b2d80SAdrian Chadd } 5646b7b2d80SAdrian Chadd 5656b7b2d80SAdrian Chadd static int 5666b7b2d80SAdrian Chadd nct_detach(device_t dev) 5676b7b2d80SAdrian Chadd { 5686b7b2d80SAdrian Chadd struct nct_softc *sc; 5696b7b2d80SAdrian Chadd 5706b7b2d80SAdrian Chadd sc = device_get_softc(dev); 5716b7b2d80SAdrian Chadd gpiobus_detach_bus(dev); 5726b7b2d80SAdrian Chadd 5736b7b2d80SAdrian Chadd GPIO_ASSERT_UNLOCKED(sc); 5746b7b2d80SAdrian Chadd GPIO_LOCK(sc); 5756b7b2d80SAdrian Chadd ext_cfg_exit(sc); 5766b7b2d80SAdrian Chadd GPIO_UNLOCK(sc); 5776b7b2d80SAdrian Chadd 5786b7b2d80SAdrian Chadd /* Cleanup resources. */ 5796b7b2d80SAdrian Chadd bus_release_resource(dev, SYS_RES_IOPORT, sc->rid, sc->portres); 5806b7b2d80SAdrian Chadd 5816b7b2d80SAdrian Chadd GPIO_LOCK_DESTROY(sc); 5826b7b2d80SAdrian Chadd 5836b7b2d80SAdrian Chadd return (0); 5846b7b2d80SAdrian Chadd } 5856b7b2d80SAdrian Chadd 5866b7b2d80SAdrian Chadd static device_t 5876b7b2d80SAdrian Chadd nct_gpio_get_bus(device_t dev) 5886b7b2d80SAdrian Chadd { 5896b7b2d80SAdrian Chadd struct nct_softc *sc; 5906b7b2d80SAdrian Chadd 5916b7b2d80SAdrian Chadd sc = device_get_softc(dev); 5926b7b2d80SAdrian Chadd 5936b7b2d80SAdrian Chadd return (sc->busdev); 5946b7b2d80SAdrian Chadd } 5956b7b2d80SAdrian Chadd 5966b7b2d80SAdrian Chadd static int 5976b7b2d80SAdrian Chadd nct_gpio_pin_max(device_t dev, int *npins) 5986b7b2d80SAdrian Chadd { 5996b7b2d80SAdrian Chadd *npins = NCT_MAX_PIN; 6006b7b2d80SAdrian Chadd 6016b7b2d80SAdrian Chadd return (0); 6026b7b2d80SAdrian Chadd } 6036b7b2d80SAdrian Chadd 6046b7b2d80SAdrian Chadd static int 6056b7b2d80SAdrian Chadd nct_gpio_pin_set(device_t dev, uint32_t pin_num, uint32_t pin_value) 6066b7b2d80SAdrian Chadd { 6076b7b2d80SAdrian Chadd struct nct_softc *sc; 6086b7b2d80SAdrian Chadd 6096b7b2d80SAdrian Chadd if (!NCT_IS_VALID_PIN(pin_num)) 6106b7b2d80SAdrian Chadd return (EINVAL); 6116b7b2d80SAdrian Chadd 6126b7b2d80SAdrian Chadd sc = device_get_softc(dev); 6136b7b2d80SAdrian Chadd GPIO_ASSERT_UNLOCKED(sc); 6146b7b2d80SAdrian Chadd GPIO_LOCK(sc); 6156b7b2d80SAdrian Chadd nct_write_pin(sc, pin_num, pin_value); 6166b7b2d80SAdrian Chadd GPIO_UNLOCK(sc); 6176b7b2d80SAdrian Chadd 6186b7b2d80SAdrian Chadd return (0); 6196b7b2d80SAdrian Chadd } 6206b7b2d80SAdrian Chadd 6216b7b2d80SAdrian Chadd static int 6226b7b2d80SAdrian Chadd nct_gpio_pin_get(device_t dev, uint32_t pin_num, uint32_t *pin_value) 6236b7b2d80SAdrian Chadd { 6246b7b2d80SAdrian Chadd struct nct_softc *sc; 6256b7b2d80SAdrian Chadd 6266b7b2d80SAdrian Chadd if (!NCT_IS_VALID_PIN(pin_num)) 6276b7b2d80SAdrian Chadd return (EINVAL); 6286b7b2d80SAdrian Chadd 6296b7b2d80SAdrian Chadd sc = device_get_softc(dev); 6306b7b2d80SAdrian Chadd GPIO_ASSERT_UNLOCKED(sc); 6316b7b2d80SAdrian Chadd GPIO_LOCK(sc); 6326b7b2d80SAdrian Chadd *pin_value = nct_read_pin(sc, pin_num); 6336b7b2d80SAdrian Chadd GPIO_UNLOCK(sc); 6346b7b2d80SAdrian Chadd 6356b7b2d80SAdrian Chadd return (0); 6366b7b2d80SAdrian Chadd } 6376b7b2d80SAdrian Chadd 6386b7b2d80SAdrian Chadd static int 6396b7b2d80SAdrian Chadd nct_gpio_pin_toggle(device_t dev, uint32_t pin_num) 6406b7b2d80SAdrian Chadd { 6416b7b2d80SAdrian Chadd struct nct_softc *sc; 6426b7b2d80SAdrian Chadd 6436b7b2d80SAdrian Chadd if (!NCT_IS_VALID_PIN(pin_num)) 6446b7b2d80SAdrian Chadd return (EINVAL); 6456b7b2d80SAdrian Chadd 6466b7b2d80SAdrian Chadd sc = device_get_softc(dev); 6476b7b2d80SAdrian Chadd GPIO_ASSERT_UNLOCKED(sc); 6486b7b2d80SAdrian Chadd GPIO_LOCK(sc); 6496b7b2d80SAdrian Chadd if (nct_read_pin(sc, pin_num)) 6506b7b2d80SAdrian Chadd nct_write_pin(sc, pin_num, 0); 6516b7b2d80SAdrian Chadd else 6526b7b2d80SAdrian Chadd nct_write_pin(sc, pin_num, 1); 6536b7b2d80SAdrian Chadd 6546b7b2d80SAdrian Chadd GPIO_UNLOCK(sc); 6556b7b2d80SAdrian Chadd 6566b7b2d80SAdrian Chadd return (0); 6576b7b2d80SAdrian Chadd } 6586b7b2d80SAdrian Chadd 6596b7b2d80SAdrian Chadd static int 6606b7b2d80SAdrian Chadd nct_gpio_pin_getcaps(device_t dev, uint32_t pin_num, uint32_t *caps) 6616b7b2d80SAdrian Chadd { 6626b7b2d80SAdrian Chadd struct nct_softc *sc; 6636b7b2d80SAdrian Chadd 6646b7b2d80SAdrian Chadd if (!NCT_IS_VALID_PIN(pin_num)) 6656b7b2d80SAdrian Chadd return (EINVAL); 6666b7b2d80SAdrian Chadd 6676b7b2d80SAdrian Chadd sc = device_get_softc(dev); 6686b7b2d80SAdrian Chadd GPIO_ASSERT_UNLOCKED(sc); 6696b7b2d80SAdrian Chadd GPIO_LOCK(sc); 6706b7b2d80SAdrian Chadd *caps = sc->pins[pin_num].gp_caps; 6716b7b2d80SAdrian Chadd GPIO_UNLOCK(sc); 6726b7b2d80SAdrian Chadd 6736b7b2d80SAdrian Chadd return (0); 6746b7b2d80SAdrian Chadd } 6756b7b2d80SAdrian Chadd 6766b7b2d80SAdrian Chadd static int 6776b7b2d80SAdrian Chadd nct_gpio_pin_getflags(device_t dev, uint32_t pin_num, uint32_t *flags) 6786b7b2d80SAdrian Chadd { 6796b7b2d80SAdrian Chadd struct nct_softc *sc; 6806b7b2d80SAdrian Chadd 6816b7b2d80SAdrian Chadd if (!NCT_IS_VALID_PIN(pin_num)) 6826b7b2d80SAdrian Chadd return (EINVAL); 6836b7b2d80SAdrian Chadd 6846b7b2d80SAdrian Chadd sc = device_get_softc(dev); 6856b7b2d80SAdrian Chadd GPIO_ASSERT_UNLOCKED(sc); 6866b7b2d80SAdrian Chadd GPIO_LOCK(sc); 6876b7b2d80SAdrian Chadd *flags = sc->pins[pin_num].gp_flags; 6886b7b2d80SAdrian Chadd GPIO_UNLOCK(sc); 6896b7b2d80SAdrian Chadd 6906b7b2d80SAdrian Chadd return (0); 6916b7b2d80SAdrian Chadd } 6926b7b2d80SAdrian Chadd 6936b7b2d80SAdrian Chadd static int 6946b7b2d80SAdrian Chadd nct_gpio_pin_getname(device_t dev, uint32_t pin_num, char *name) 6956b7b2d80SAdrian Chadd { 6966b7b2d80SAdrian Chadd struct nct_softc *sc; 6976b7b2d80SAdrian Chadd 6986b7b2d80SAdrian Chadd if (!NCT_IS_VALID_PIN(pin_num)) 6996b7b2d80SAdrian Chadd return (EINVAL); 7006b7b2d80SAdrian Chadd 7016b7b2d80SAdrian Chadd sc = device_get_softc(dev); 7026b7b2d80SAdrian Chadd GPIO_ASSERT_UNLOCKED(sc); 7036b7b2d80SAdrian Chadd GPIO_LOCK(sc); 7046b7b2d80SAdrian Chadd memcpy(name, sc->pins[pin_num].gp_name, GPIOMAXNAME); 7056b7b2d80SAdrian Chadd GPIO_UNLOCK(sc); 7066b7b2d80SAdrian Chadd 7076b7b2d80SAdrian Chadd return (0); 7086b7b2d80SAdrian Chadd } 7096b7b2d80SAdrian Chadd 7106b7b2d80SAdrian Chadd static int 7116b7b2d80SAdrian Chadd nct_gpio_pin_setflags(device_t dev, uint32_t pin_num, uint32_t flags) 7126b7b2d80SAdrian Chadd { 7136b7b2d80SAdrian Chadd struct nct_softc *sc; 7146b7b2d80SAdrian Chadd struct gpio_pin *pin; 7156b7b2d80SAdrian Chadd 7166b7b2d80SAdrian Chadd if (!NCT_IS_VALID_PIN(pin_num)) 7176b7b2d80SAdrian Chadd return (EINVAL); 7186b7b2d80SAdrian Chadd 7196b7b2d80SAdrian Chadd sc = device_get_softc(dev); 7206b7b2d80SAdrian Chadd pin = &sc->pins[pin_num]; 7216b7b2d80SAdrian Chadd if ((flags & pin->gp_caps) != flags) 7226b7b2d80SAdrian Chadd return (EINVAL); 7236b7b2d80SAdrian Chadd 7246b7b2d80SAdrian Chadd GPIO_ASSERT_UNLOCKED(sc); 7256b7b2d80SAdrian Chadd GPIO_LOCK(sc); 7266b7b2d80SAdrian Chadd if (flags & (GPIO_PIN_INPUT | GPIO_PIN_OUTPUT)) { 7276b7b2d80SAdrian Chadd if ((flags & (GPIO_PIN_INPUT | GPIO_PIN_OUTPUT)) == 7286b7b2d80SAdrian Chadd (GPIO_PIN_INPUT | GPIO_PIN_OUTPUT)) { 7296b7b2d80SAdrian Chadd GPIO_UNLOCK(sc); 7306b7b2d80SAdrian Chadd return (EINVAL); 7316b7b2d80SAdrian Chadd } 7326b7b2d80SAdrian Chadd 7336b7b2d80SAdrian Chadd if (flags & GPIO_PIN_INPUT) 7346b7b2d80SAdrian Chadd nct_set_pin_is_input(sc, pin_num); 7356b7b2d80SAdrian Chadd else 7366b7b2d80SAdrian Chadd nct_set_pin_is_output(sc, pin_num); 7376b7b2d80SAdrian Chadd } 7386b7b2d80SAdrian Chadd 7396b7b2d80SAdrian Chadd if (flags & (GPIO_PIN_OPENDRAIN | GPIO_PIN_PUSHPULL)) { 7406b7b2d80SAdrian Chadd if (flags & GPIO_PIN_INPUT) { 7416b7b2d80SAdrian Chadd GPIO_UNLOCK(sc); 7426b7b2d80SAdrian Chadd return (EINVAL); 7436b7b2d80SAdrian Chadd } 7446b7b2d80SAdrian Chadd 7456b7b2d80SAdrian Chadd if ((flags & (GPIO_PIN_OPENDRAIN | GPIO_PIN_PUSHPULL)) == 7466b7b2d80SAdrian Chadd (GPIO_PIN_OPENDRAIN | GPIO_PIN_PUSHPULL)) { 7476b7b2d80SAdrian Chadd GPIO_UNLOCK(sc); 7486b7b2d80SAdrian Chadd return (EINVAL); 7496b7b2d80SAdrian Chadd } 7506b7b2d80SAdrian Chadd 7516b7b2d80SAdrian Chadd if (flags & GPIO_PIN_OPENDRAIN) 7526b7b2d80SAdrian Chadd nct_set_pin_opendrain(sc, pin_num); 7536b7b2d80SAdrian Chadd else 7546b7b2d80SAdrian Chadd nct_set_pin_pushpull(sc, pin_num); 7556b7b2d80SAdrian Chadd } 7566b7b2d80SAdrian Chadd 7576b7b2d80SAdrian Chadd if (flags & (GPIO_PIN_INVIN | GPIO_PIN_INVOUT)) { 7586b7b2d80SAdrian Chadd if ((flags & (GPIO_PIN_INVIN | GPIO_PIN_INVOUT)) != 7596b7b2d80SAdrian Chadd (GPIO_PIN_INVIN | GPIO_PIN_INVOUT)) { 7606b7b2d80SAdrian Chadd GPIO_UNLOCK(sc); 7616b7b2d80SAdrian Chadd return (EINVAL); 7626b7b2d80SAdrian Chadd } 7636b7b2d80SAdrian Chadd 7646b7b2d80SAdrian Chadd if (flags & GPIO_PIN_INVIN) 7656b7b2d80SAdrian Chadd nct_set_pin_is_inverted(sc, pin_num); 7666b7b2d80SAdrian Chadd else 7676b7b2d80SAdrian Chadd nct_set_pin_not_inverted(sc, pin_num); 7686b7b2d80SAdrian Chadd } 7696b7b2d80SAdrian Chadd 7706b7b2d80SAdrian Chadd pin->gp_flags = flags; 7716b7b2d80SAdrian Chadd GPIO_UNLOCK(sc); 7726b7b2d80SAdrian Chadd 7736b7b2d80SAdrian Chadd return (0); 7746b7b2d80SAdrian Chadd } 7756b7b2d80SAdrian Chadd 7766b7b2d80SAdrian Chadd static device_method_t nct_methods[] = { 7776b7b2d80SAdrian Chadd /* Device interface */ 7786b7b2d80SAdrian Chadd DEVMETHOD(device_identify, nct_identify), 7796b7b2d80SAdrian Chadd DEVMETHOD(device_probe, nct_probe), 7806b7b2d80SAdrian Chadd DEVMETHOD(device_attach, nct_attach), 7816b7b2d80SAdrian Chadd DEVMETHOD(device_detach, nct_detach), 7826b7b2d80SAdrian Chadd 7836b7b2d80SAdrian Chadd /* GPIO */ 7846b7b2d80SAdrian Chadd DEVMETHOD(gpio_get_bus, nct_gpio_get_bus), 7856b7b2d80SAdrian Chadd DEVMETHOD(gpio_pin_max, nct_gpio_pin_max), 7866b7b2d80SAdrian Chadd DEVMETHOD(gpio_pin_get, nct_gpio_pin_get), 7876b7b2d80SAdrian Chadd DEVMETHOD(gpio_pin_set, nct_gpio_pin_set), 7886b7b2d80SAdrian Chadd DEVMETHOD(gpio_pin_toggle, nct_gpio_pin_toggle), 7896b7b2d80SAdrian Chadd DEVMETHOD(gpio_pin_getname, nct_gpio_pin_getname), 7906b7b2d80SAdrian Chadd DEVMETHOD(gpio_pin_getcaps, nct_gpio_pin_getcaps), 7916b7b2d80SAdrian Chadd DEVMETHOD(gpio_pin_getflags, nct_gpio_pin_getflags), 7926b7b2d80SAdrian Chadd DEVMETHOD(gpio_pin_setflags, nct_gpio_pin_setflags), 7936b7b2d80SAdrian Chadd 7946b7b2d80SAdrian Chadd DEVMETHOD_END 7956b7b2d80SAdrian Chadd }; 7966b7b2d80SAdrian Chadd 7976b7b2d80SAdrian Chadd static driver_t nct_isa_driver = { 7986b7b2d80SAdrian Chadd "gpio", 7996b7b2d80SAdrian Chadd nct_methods, 8006b7b2d80SAdrian Chadd sizeof(struct nct_softc) 8016b7b2d80SAdrian Chadd }; 8026b7b2d80SAdrian Chadd 8036b7b2d80SAdrian Chadd static devclass_t nct_devclass; 8046b7b2d80SAdrian Chadd 8056b7b2d80SAdrian Chadd DRIVER_MODULE(nctgpio, isa, nct_isa_driver, nct_devclass, NULL, NULL); 8066b7b2d80SAdrian Chadd MODULE_DEPEND(nctgpio, gpiobus, 1, 1, 1); 807