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