1*6b7b2d80SAdrian Chadd /*- 2*6b7b2d80SAdrian Chadd * Copyright (c) 2016 Daniel Wyatt <Daniel.Wyatt@gmail.com> 3*6b7b2d80SAdrian Chadd * All rights reserved. 4*6b7b2d80SAdrian Chadd * 5*6b7b2d80SAdrian Chadd * Redistribution and use in source and binary forms, with or without 6*6b7b2d80SAdrian Chadd * modification, are permitted provided that the following conditions 7*6b7b2d80SAdrian Chadd * are met: 8*6b7b2d80SAdrian Chadd * 1. Redistributions of source code must retain the above copyright 9*6b7b2d80SAdrian Chadd * notice, this list of conditions and the following disclaimer. 10*6b7b2d80SAdrian Chadd * 2. Redistributions in binary form must reproduce the above copyright 11*6b7b2d80SAdrian Chadd * notice, this list of conditions and the following disclaimer in the 12*6b7b2d80SAdrian Chadd * documentation and/or other materials provided with the distribution. 13*6b7b2d80SAdrian Chadd * 14*6b7b2d80SAdrian Chadd * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND 15*6b7b2d80SAdrian Chadd * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 16*6b7b2d80SAdrian Chadd * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 17*6b7b2d80SAdrian Chadd * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE 18*6b7b2d80SAdrian Chadd * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 19*6b7b2d80SAdrian Chadd * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 20*6b7b2d80SAdrian Chadd * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 21*6b7b2d80SAdrian Chadd * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 22*6b7b2d80SAdrian Chadd * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 23*6b7b2d80SAdrian Chadd * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 24*6b7b2d80SAdrian Chadd * SUCH DAMAGE. 25*6b7b2d80SAdrian Chadd * 26*6b7b2d80SAdrian Chadd * $FreeBSD$ 27*6b7b2d80SAdrian Chadd * 28*6b7b2d80SAdrian Chadd */ 29*6b7b2d80SAdrian Chadd 30*6b7b2d80SAdrian Chadd /* 31*6b7b2d80SAdrian Chadd * Nuvoton GPIO driver. 32*6b7b2d80SAdrian Chadd * 33*6b7b2d80SAdrian Chadd */ 34*6b7b2d80SAdrian Chadd 35*6b7b2d80SAdrian Chadd #include <sys/cdefs.h> 36*6b7b2d80SAdrian Chadd 37*6b7b2d80SAdrian Chadd #include <sys/param.h> 38*6b7b2d80SAdrian Chadd #include <sys/kernel.h> 39*6b7b2d80SAdrian Chadd #include <sys/systm.h> 40*6b7b2d80SAdrian Chadd #include <sys/bus.h> 41*6b7b2d80SAdrian Chadd #include <sys/eventhandler.h> 42*6b7b2d80SAdrian Chadd #include <sys/lock.h> 43*6b7b2d80SAdrian Chadd 44*6b7b2d80SAdrian Chadd #include <sys/module.h> 45*6b7b2d80SAdrian Chadd #include <sys/rman.h> 46*6b7b2d80SAdrian Chadd #include <sys/gpio.h> 47*6b7b2d80SAdrian Chadd 48*6b7b2d80SAdrian Chadd #include <isa/isavar.h> 49*6b7b2d80SAdrian Chadd 50*6b7b2d80SAdrian Chadd #include <machine/bus.h> 51*6b7b2d80SAdrian Chadd #include <machine/resource.h> 52*6b7b2d80SAdrian Chadd 53*6b7b2d80SAdrian Chadd #include <dev/gpio/gpiobusvar.h> 54*6b7b2d80SAdrian Chadd 55*6b7b2d80SAdrian Chadd #include "gpio_if.h" 56*6b7b2d80SAdrian Chadd 57*6b7b2d80SAdrian Chadd /* 58*6b7b2d80SAdrian Chadd * Global configuration registers (CR). 59*6b7b2d80SAdrian Chadd */ 60*6b7b2d80SAdrian Chadd #define NCT_CR_LDN 0x07 /* Logical Device Number */ 61*6b7b2d80SAdrian Chadd #define NCT_CR_CHIP_ID 0x20 /* Chip ID */ 62*6b7b2d80SAdrian Chadd #define NCT_CR_CHIP_ID_H 0x20 /* Chip ID (high byte) */ 63*6b7b2d80SAdrian Chadd #define NCT_CR_CHIP_ID_L 0x21 /* Chip ID (low byte) */ 64*6b7b2d80SAdrian Chadd #define NCT_CR_OPT_1 0x26 /* Global Options (1) */ 65*6b7b2d80SAdrian Chadd 66*6b7b2d80SAdrian Chadd /* Logical Device Numbers. */ 67*6b7b2d80SAdrian Chadd #define NCT_LDN_GPIO 0x07 68*6b7b2d80SAdrian Chadd #define NCT_LDN_GPIO_CFG 0x08 69*6b7b2d80SAdrian Chadd #define NCT_LDN_GPIO_MODE 0x0f 70*6b7b2d80SAdrian Chadd 71*6b7b2d80SAdrian Chadd /* Logical Device 7 */ 72*6b7b2d80SAdrian Chadd #define NCT_LD7_GPIO_ENABLE 0x30 73*6b7b2d80SAdrian Chadd #define NCT_LD7_GPIO0_IOR 0xe0 74*6b7b2d80SAdrian Chadd #define NCT_LD7_GPIO0_DAT 0xe1 75*6b7b2d80SAdrian Chadd #define NCT_LD7_GPIO0_INV 0xe2 76*6b7b2d80SAdrian Chadd #define NCT_LD7_GPIO0_DST 0xe3 77*6b7b2d80SAdrian Chadd #define NCT_LD7_GPIO1_IOR 0xe4 78*6b7b2d80SAdrian Chadd #define NCT_LD7_GPIO1_DAT 0xe5 79*6b7b2d80SAdrian Chadd #define NCT_LD7_GPIO1_INV 0xe6 80*6b7b2d80SAdrian Chadd #define NCT_LD7_GPIO1_DST 0xe7 81*6b7b2d80SAdrian Chadd 82*6b7b2d80SAdrian Chadd /* Logical Device F */ 83*6b7b2d80SAdrian Chadd #define NCT_LDF_GPIO0_OUTCFG 0xe0 84*6b7b2d80SAdrian Chadd #define NCT_LDF_GPIO1_OUTCFG 0xe1 85*6b7b2d80SAdrian Chadd 86*6b7b2d80SAdrian Chadd #define NCT_EXTFUNC_ENTER 0x87 87*6b7b2d80SAdrian Chadd #define NCT_EXTFUNC_EXIT 0xaa 88*6b7b2d80SAdrian Chadd 89*6b7b2d80SAdrian Chadd #define NCT_MAX_PIN 15 90*6b7b2d80SAdrian Chadd #define NCT_IS_VALID_PIN(_p) ((_p) >= 0 && (_p) <= NCT_MAX_PIN) 91*6b7b2d80SAdrian Chadd 92*6b7b2d80SAdrian Chadd #define NCT_PIN_BIT(_p) (1 << ((_p) % 8)) 93*6b7b2d80SAdrian Chadd 94*6b7b2d80SAdrian Chadd #define NCT_GPIO_CAPS (GPIO_PIN_INPUT | GPIO_PIN_OUTPUT | \ 95*6b7b2d80SAdrian Chadd GPIO_PIN_OPENDRAIN | GPIO_PIN_PUSHPULL | \ 96*6b7b2d80SAdrian Chadd GPIO_PIN_INVIN | GPIO_PIN_INVOUT) 97*6b7b2d80SAdrian Chadd 98*6b7b2d80SAdrian Chadd struct nct_softc { 99*6b7b2d80SAdrian Chadd device_t dev; 100*6b7b2d80SAdrian Chadd device_t busdev; 101*6b7b2d80SAdrian Chadd struct mtx mtx; 102*6b7b2d80SAdrian Chadd struct resource *portres; 103*6b7b2d80SAdrian Chadd int rid; 104*6b7b2d80SAdrian Chadd struct gpio_pin pins[NCT_MAX_PIN]; 105*6b7b2d80SAdrian Chadd }; 106*6b7b2d80SAdrian Chadd 107*6b7b2d80SAdrian Chadd #define GPIO_LOCK_INIT(_sc) mtx_init(&(_sc)->mtx, \ 108*6b7b2d80SAdrian Chadd device_get_nameunit(dev), NULL, MTX_DEF) 109*6b7b2d80SAdrian Chadd #define GPIO_LOCK_DESTROY(_sc) mtx_destroy(&(_sc)->mtx) 110*6b7b2d80SAdrian Chadd #define GPIO_LOCK(_sc) mtx_lock(&(_sc)->mtx) 111*6b7b2d80SAdrian Chadd #define GPIO_UNLOCK(_sc) mtx_unlock(&(_sc)->mtx) 112*6b7b2d80SAdrian Chadd #define GPIO_ASSERT_LOCKED(_sc) mtx_assert(&(_sc)->mtx, MA_OWNED) 113*6b7b2d80SAdrian Chadd #define GPIO_ASSERT_UNLOCKED(_sc) mtx_assert(&(_sc)->mtx, MA_NOTOWNED) 114*6b7b2d80SAdrian Chadd 115*6b7b2d80SAdrian Chadd #define NCT_BARRIER_WRITE(_sc) \ 116*6b7b2d80SAdrian Chadd bus_barrier((_sc)->portres, 0, 2, BUS_SPACE_BARRIER_WRITE) 117*6b7b2d80SAdrian Chadd 118*6b7b2d80SAdrian Chadd #define NCT_BARRIER_READ_WRITE(_sc) \ 119*6b7b2d80SAdrian Chadd bus_barrier((_sc)->portres, 0, 2, \ 120*6b7b2d80SAdrian Chadd BUS_SPACE_BARRIER_READ | BUS_SPACE_BARRIER_WRITE) 121*6b7b2d80SAdrian Chadd 122*6b7b2d80SAdrian Chadd static void ext_cfg_enter(struct nct_softc *); 123*6b7b2d80SAdrian Chadd static void ext_cfg_exit(struct nct_softc *); 124*6b7b2d80SAdrian Chadd 125*6b7b2d80SAdrian Chadd /* 126*6b7b2d80SAdrian Chadd * Potential Extended Function Enable Register addresses. 127*6b7b2d80SAdrian Chadd * Same address as EFIR. 128*6b7b2d80SAdrian Chadd */ 129*6b7b2d80SAdrian Chadd uint8_t probe_addrs[] = {0x2e, 0x4e}; 130*6b7b2d80SAdrian Chadd 131*6b7b2d80SAdrian Chadd struct nuvoton_vendor_device_id { 132*6b7b2d80SAdrian Chadd uint16_t chip_id; 133*6b7b2d80SAdrian Chadd const char * descr; 134*6b7b2d80SAdrian Chadd } nct_devs[] = { 135*6b7b2d80SAdrian Chadd { 136*6b7b2d80SAdrian Chadd .chip_id = 0x1061, 137*6b7b2d80SAdrian Chadd .descr = "Nuvoton NCT5104D", 138*6b7b2d80SAdrian Chadd }, 139*6b7b2d80SAdrian Chadd { 140*6b7b2d80SAdrian Chadd .chip_id = 0xc452, 141*6b7b2d80SAdrian Chadd .descr = "Nuvoton NCT5104D (PC-Engines APU)", 142*6b7b2d80SAdrian Chadd }, 143*6b7b2d80SAdrian Chadd }; 144*6b7b2d80SAdrian Chadd 145*6b7b2d80SAdrian Chadd static void 146*6b7b2d80SAdrian Chadd write_cfg_reg_1(struct nct_softc *sc, uint8_t reg, uint8_t value) 147*6b7b2d80SAdrian Chadd { 148*6b7b2d80SAdrian Chadd GPIO_ASSERT_LOCKED(sc); 149*6b7b2d80SAdrian Chadd bus_write_1(sc->portres, 0, reg); 150*6b7b2d80SAdrian Chadd NCT_BARRIER_WRITE(sc); 151*6b7b2d80SAdrian Chadd bus_write_1(sc->portres, 1, value); 152*6b7b2d80SAdrian Chadd NCT_BARRIER_WRITE(sc); 153*6b7b2d80SAdrian Chadd } 154*6b7b2d80SAdrian Chadd 155*6b7b2d80SAdrian Chadd static uint8_t 156*6b7b2d80SAdrian Chadd read_cfg_reg_1(struct nct_softc *sc, uint8_t reg) 157*6b7b2d80SAdrian Chadd { 158*6b7b2d80SAdrian Chadd uint8_t value; 159*6b7b2d80SAdrian Chadd 160*6b7b2d80SAdrian Chadd GPIO_ASSERT_LOCKED(sc); 161*6b7b2d80SAdrian Chadd bus_write_1(sc->portres, 0, reg); 162*6b7b2d80SAdrian Chadd NCT_BARRIER_READ_WRITE(sc); 163*6b7b2d80SAdrian Chadd value = bus_read_1(sc->portres, 1); 164*6b7b2d80SAdrian Chadd NCT_BARRIER_READ_WRITE(sc); 165*6b7b2d80SAdrian Chadd 166*6b7b2d80SAdrian Chadd return (value); 167*6b7b2d80SAdrian Chadd } 168*6b7b2d80SAdrian Chadd 169*6b7b2d80SAdrian Chadd static uint16_t 170*6b7b2d80SAdrian Chadd read_cfg_reg_2(struct nct_softc *sc, uint8_t reg) 171*6b7b2d80SAdrian Chadd { 172*6b7b2d80SAdrian Chadd uint16_t value; 173*6b7b2d80SAdrian Chadd 174*6b7b2d80SAdrian Chadd value = read_cfg_reg_1(sc, reg) << 8; 175*6b7b2d80SAdrian Chadd value |= read_cfg_reg_1(sc, reg + 1); 176*6b7b2d80SAdrian Chadd 177*6b7b2d80SAdrian Chadd return (value); 178*6b7b2d80SAdrian Chadd } 179*6b7b2d80SAdrian Chadd 180*6b7b2d80SAdrian Chadd /* 181*6b7b2d80SAdrian Chadd * Enable extended function mode. 182*6b7b2d80SAdrian Chadd * 183*6b7b2d80SAdrian Chadd */ 184*6b7b2d80SAdrian Chadd static void 185*6b7b2d80SAdrian Chadd ext_cfg_enter(struct nct_softc *sc) 186*6b7b2d80SAdrian Chadd { 187*6b7b2d80SAdrian Chadd GPIO_ASSERT_LOCKED(sc); 188*6b7b2d80SAdrian Chadd bus_write_1(sc->portres, 0, NCT_EXTFUNC_ENTER); 189*6b7b2d80SAdrian Chadd NCT_BARRIER_WRITE(sc); 190*6b7b2d80SAdrian Chadd bus_write_1(sc->portres, 0, NCT_EXTFUNC_ENTER); 191*6b7b2d80SAdrian Chadd NCT_BARRIER_WRITE(sc); 192*6b7b2d80SAdrian Chadd } 193*6b7b2d80SAdrian Chadd 194*6b7b2d80SAdrian Chadd /* 195*6b7b2d80SAdrian Chadd * Disable extended function mode. 196*6b7b2d80SAdrian Chadd * 197*6b7b2d80SAdrian Chadd */ 198*6b7b2d80SAdrian Chadd static void 199*6b7b2d80SAdrian Chadd ext_cfg_exit(struct nct_softc *sc) 200*6b7b2d80SAdrian Chadd { 201*6b7b2d80SAdrian Chadd GPIO_ASSERT_LOCKED(sc); 202*6b7b2d80SAdrian Chadd bus_write_1(sc->portres, 0, NCT_EXTFUNC_EXIT); 203*6b7b2d80SAdrian Chadd NCT_BARRIER_WRITE(sc); 204*6b7b2d80SAdrian Chadd } 205*6b7b2d80SAdrian Chadd 206*6b7b2d80SAdrian Chadd /* 207*6b7b2d80SAdrian Chadd * Select a Logical Device. 208*6b7b2d80SAdrian Chadd */ 209*6b7b2d80SAdrian Chadd static void 210*6b7b2d80SAdrian Chadd select_ldn(struct nct_softc *sc, uint8_t ldn) 211*6b7b2d80SAdrian Chadd { 212*6b7b2d80SAdrian Chadd write_cfg_reg_1(sc, NCT_CR_LDN, ldn); 213*6b7b2d80SAdrian Chadd } 214*6b7b2d80SAdrian Chadd 215*6b7b2d80SAdrian Chadd /* 216*6b7b2d80SAdrian Chadd * Get the GPIO Input/Output register address 217*6b7b2d80SAdrian Chadd * for a pin. 218*6b7b2d80SAdrian Chadd */ 219*6b7b2d80SAdrian Chadd static uint8_t 220*6b7b2d80SAdrian Chadd nct_ior_addr(uint32_t pin_num) 221*6b7b2d80SAdrian Chadd { 222*6b7b2d80SAdrian Chadd uint8_t addr; 223*6b7b2d80SAdrian Chadd 224*6b7b2d80SAdrian Chadd addr = NCT_LD7_GPIO0_IOR; 225*6b7b2d80SAdrian Chadd if (pin_num > 7) 226*6b7b2d80SAdrian Chadd addr = NCT_LD7_GPIO1_IOR; 227*6b7b2d80SAdrian Chadd 228*6b7b2d80SAdrian Chadd return (addr); 229*6b7b2d80SAdrian Chadd } 230*6b7b2d80SAdrian Chadd 231*6b7b2d80SAdrian Chadd /* 232*6b7b2d80SAdrian Chadd * Get the GPIO Data register address for a pin. 233*6b7b2d80SAdrian Chadd */ 234*6b7b2d80SAdrian Chadd static uint8_t 235*6b7b2d80SAdrian Chadd nct_dat_addr(uint32_t pin_num) 236*6b7b2d80SAdrian Chadd { 237*6b7b2d80SAdrian Chadd uint8_t addr; 238*6b7b2d80SAdrian Chadd 239*6b7b2d80SAdrian Chadd addr = NCT_LD7_GPIO0_DAT; 240*6b7b2d80SAdrian Chadd if (pin_num > 7) 241*6b7b2d80SAdrian Chadd addr = NCT_LD7_GPIO1_DAT; 242*6b7b2d80SAdrian Chadd 243*6b7b2d80SAdrian Chadd return (addr); 244*6b7b2d80SAdrian Chadd } 245*6b7b2d80SAdrian Chadd 246*6b7b2d80SAdrian Chadd /* 247*6b7b2d80SAdrian Chadd * Get the GPIO Inversion register address 248*6b7b2d80SAdrian Chadd * for a pin. 249*6b7b2d80SAdrian Chadd */ 250*6b7b2d80SAdrian Chadd static uint8_t 251*6b7b2d80SAdrian Chadd nct_inv_addr(uint32_t pin_num) 252*6b7b2d80SAdrian Chadd { 253*6b7b2d80SAdrian Chadd uint8_t addr; 254*6b7b2d80SAdrian Chadd 255*6b7b2d80SAdrian Chadd addr = NCT_LD7_GPIO0_INV; 256*6b7b2d80SAdrian Chadd if (pin_num > 7) 257*6b7b2d80SAdrian Chadd addr = NCT_LD7_GPIO1_INV; 258*6b7b2d80SAdrian Chadd 259*6b7b2d80SAdrian Chadd return (addr); 260*6b7b2d80SAdrian Chadd } 261*6b7b2d80SAdrian Chadd 262*6b7b2d80SAdrian Chadd /* 263*6b7b2d80SAdrian Chadd * Get the GPIO Output Configuration/Mode 264*6b7b2d80SAdrian Chadd * register address for a pin. 265*6b7b2d80SAdrian Chadd */ 266*6b7b2d80SAdrian Chadd static uint8_t 267*6b7b2d80SAdrian Chadd nct_outcfg_addr(uint32_t pin_num) 268*6b7b2d80SAdrian Chadd { 269*6b7b2d80SAdrian Chadd uint8_t addr; 270*6b7b2d80SAdrian Chadd 271*6b7b2d80SAdrian Chadd addr = NCT_LDF_GPIO0_OUTCFG; 272*6b7b2d80SAdrian Chadd if (pin_num > 7) 273*6b7b2d80SAdrian Chadd addr = NCT_LDF_GPIO1_OUTCFG; 274*6b7b2d80SAdrian Chadd 275*6b7b2d80SAdrian Chadd return (addr); 276*6b7b2d80SAdrian Chadd } 277*6b7b2d80SAdrian Chadd 278*6b7b2d80SAdrian Chadd /* 279*6b7b2d80SAdrian Chadd * Set a pin to output mode. 280*6b7b2d80SAdrian Chadd */ 281*6b7b2d80SAdrian Chadd static void 282*6b7b2d80SAdrian Chadd nct_set_pin_is_output(struct nct_softc *sc, uint32_t pin_num) 283*6b7b2d80SAdrian Chadd { 284*6b7b2d80SAdrian Chadd uint8_t reg; 285*6b7b2d80SAdrian Chadd uint8_t ior; 286*6b7b2d80SAdrian Chadd 287*6b7b2d80SAdrian Chadd reg = nct_ior_addr(pin_num); 288*6b7b2d80SAdrian Chadd select_ldn(sc, NCT_LDN_GPIO); 289*6b7b2d80SAdrian Chadd ior = read_cfg_reg_1(sc, reg); 290*6b7b2d80SAdrian Chadd ior &= ~(NCT_PIN_BIT(pin_num)); 291*6b7b2d80SAdrian Chadd write_cfg_reg_1(sc, reg, ior); 292*6b7b2d80SAdrian Chadd } 293*6b7b2d80SAdrian Chadd 294*6b7b2d80SAdrian Chadd /* 295*6b7b2d80SAdrian Chadd * Set a pin to input mode. 296*6b7b2d80SAdrian Chadd */ 297*6b7b2d80SAdrian Chadd static void 298*6b7b2d80SAdrian Chadd nct_set_pin_is_input(struct nct_softc *sc, uint32_t pin_num) 299*6b7b2d80SAdrian Chadd { 300*6b7b2d80SAdrian Chadd uint8_t reg; 301*6b7b2d80SAdrian Chadd uint8_t ior; 302*6b7b2d80SAdrian Chadd 303*6b7b2d80SAdrian Chadd reg = nct_ior_addr(pin_num); 304*6b7b2d80SAdrian Chadd select_ldn(sc, NCT_LDN_GPIO); 305*6b7b2d80SAdrian Chadd ior = read_cfg_reg_1(sc, reg); 306*6b7b2d80SAdrian Chadd ior |= NCT_PIN_BIT(pin_num); 307*6b7b2d80SAdrian Chadd write_cfg_reg_1(sc, reg, ior); 308*6b7b2d80SAdrian Chadd } 309*6b7b2d80SAdrian Chadd 310*6b7b2d80SAdrian Chadd /* 311*6b7b2d80SAdrian Chadd * Check whether a pin is configured as an input. 312*6b7b2d80SAdrian Chadd */ 313*6b7b2d80SAdrian Chadd static bool 314*6b7b2d80SAdrian Chadd nct_pin_is_input(struct nct_softc *sc, uint32_t pin_num) 315*6b7b2d80SAdrian Chadd { 316*6b7b2d80SAdrian Chadd uint8_t reg; 317*6b7b2d80SAdrian Chadd uint8_t ior; 318*6b7b2d80SAdrian Chadd 319*6b7b2d80SAdrian Chadd reg = nct_ior_addr(pin_num); 320*6b7b2d80SAdrian Chadd select_ldn(sc, NCT_LDN_GPIO); 321*6b7b2d80SAdrian Chadd ior = read_cfg_reg_1(sc, reg); 322*6b7b2d80SAdrian Chadd 323*6b7b2d80SAdrian Chadd return (ior & NCT_PIN_BIT(pin_num)); 324*6b7b2d80SAdrian Chadd } 325*6b7b2d80SAdrian Chadd 326*6b7b2d80SAdrian Chadd /* 327*6b7b2d80SAdrian Chadd * Write a value to an output pin. 328*6b7b2d80SAdrian Chadd */ 329*6b7b2d80SAdrian Chadd static void 330*6b7b2d80SAdrian Chadd nct_write_pin(struct nct_softc *sc, uint32_t pin_num, uint8_t data) 331*6b7b2d80SAdrian Chadd { 332*6b7b2d80SAdrian Chadd uint8_t reg; 333*6b7b2d80SAdrian Chadd uint8_t value; 334*6b7b2d80SAdrian Chadd 335*6b7b2d80SAdrian Chadd reg = nct_dat_addr(pin_num); 336*6b7b2d80SAdrian Chadd select_ldn(sc, NCT_LDN_GPIO); 337*6b7b2d80SAdrian Chadd value = read_cfg_reg_1(sc, reg); 338*6b7b2d80SAdrian Chadd if (data) 339*6b7b2d80SAdrian Chadd value |= NCT_PIN_BIT(pin_num); 340*6b7b2d80SAdrian Chadd else 341*6b7b2d80SAdrian Chadd value &= ~(NCT_PIN_BIT(pin_num)); 342*6b7b2d80SAdrian Chadd 343*6b7b2d80SAdrian Chadd write_cfg_reg_1(sc, reg, value); 344*6b7b2d80SAdrian Chadd } 345*6b7b2d80SAdrian Chadd 346*6b7b2d80SAdrian Chadd static bool 347*6b7b2d80SAdrian Chadd nct_read_pin(struct nct_softc *sc, uint32_t pin_num) 348*6b7b2d80SAdrian Chadd { 349*6b7b2d80SAdrian Chadd uint8_t reg; 350*6b7b2d80SAdrian Chadd 351*6b7b2d80SAdrian Chadd reg = nct_dat_addr(pin_num); 352*6b7b2d80SAdrian Chadd select_ldn(sc, NCT_LDN_GPIO); 353*6b7b2d80SAdrian Chadd 354*6b7b2d80SAdrian Chadd return (read_cfg_reg_1(sc, reg) & NCT_PIN_BIT(pin_num)); 355*6b7b2d80SAdrian Chadd } 356*6b7b2d80SAdrian Chadd 357*6b7b2d80SAdrian Chadd static void 358*6b7b2d80SAdrian Chadd nct_set_pin_is_inverted(struct nct_softc *sc, uint32_t pin_num) 359*6b7b2d80SAdrian Chadd { 360*6b7b2d80SAdrian Chadd uint8_t reg; 361*6b7b2d80SAdrian Chadd uint8_t inv; 362*6b7b2d80SAdrian Chadd 363*6b7b2d80SAdrian Chadd reg = nct_inv_addr(pin_num); 364*6b7b2d80SAdrian Chadd select_ldn(sc, NCT_LDN_GPIO); 365*6b7b2d80SAdrian Chadd inv = read_cfg_reg_1(sc, reg); 366*6b7b2d80SAdrian Chadd inv |= (NCT_PIN_BIT(pin_num)); 367*6b7b2d80SAdrian Chadd write_cfg_reg_1(sc, reg, inv); 368*6b7b2d80SAdrian Chadd } 369*6b7b2d80SAdrian Chadd 370*6b7b2d80SAdrian Chadd static void 371*6b7b2d80SAdrian Chadd nct_set_pin_not_inverted(struct nct_softc *sc, uint32_t pin_num) 372*6b7b2d80SAdrian Chadd { 373*6b7b2d80SAdrian Chadd uint8_t reg; 374*6b7b2d80SAdrian Chadd uint8_t inv; 375*6b7b2d80SAdrian Chadd 376*6b7b2d80SAdrian Chadd reg = nct_inv_addr(pin_num); 377*6b7b2d80SAdrian Chadd select_ldn(sc, NCT_LDN_GPIO); 378*6b7b2d80SAdrian Chadd inv = read_cfg_reg_1(sc, reg); 379*6b7b2d80SAdrian Chadd inv &= ~(NCT_PIN_BIT(pin_num)); 380*6b7b2d80SAdrian Chadd write_cfg_reg_1(sc, reg, inv); 381*6b7b2d80SAdrian Chadd } 382*6b7b2d80SAdrian Chadd 383*6b7b2d80SAdrian Chadd static bool 384*6b7b2d80SAdrian Chadd nct_pin_is_inverted(struct nct_softc *sc, uint32_t pin_num) 385*6b7b2d80SAdrian Chadd { 386*6b7b2d80SAdrian Chadd uint8_t reg; 387*6b7b2d80SAdrian Chadd uint8_t inv; 388*6b7b2d80SAdrian Chadd 389*6b7b2d80SAdrian Chadd reg = nct_inv_addr(pin_num); 390*6b7b2d80SAdrian Chadd select_ldn(sc, NCT_LDN_GPIO); 391*6b7b2d80SAdrian Chadd inv = read_cfg_reg_1(sc, reg); 392*6b7b2d80SAdrian Chadd 393*6b7b2d80SAdrian Chadd return (inv & NCT_PIN_BIT(pin_num)); 394*6b7b2d80SAdrian Chadd } 395*6b7b2d80SAdrian Chadd 396*6b7b2d80SAdrian Chadd static void 397*6b7b2d80SAdrian Chadd nct_set_pin_opendrain(struct nct_softc *sc, uint32_t pin_num) 398*6b7b2d80SAdrian Chadd { 399*6b7b2d80SAdrian Chadd uint8_t reg; 400*6b7b2d80SAdrian Chadd uint8_t outcfg; 401*6b7b2d80SAdrian Chadd 402*6b7b2d80SAdrian Chadd reg = nct_outcfg_addr(pin_num); 403*6b7b2d80SAdrian Chadd select_ldn(sc, NCT_LDN_GPIO_MODE); 404*6b7b2d80SAdrian Chadd outcfg = read_cfg_reg_1(sc, reg); 405*6b7b2d80SAdrian Chadd outcfg |= (NCT_PIN_BIT(pin_num)); 406*6b7b2d80SAdrian Chadd write_cfg_reg_1(sc, reg, outcfg); 407*6b7b2d80SAdrian Chadd } 408*6b7b2d80SAdrian Chadd 409*6b7b2d80SAdrian Chadd static void 410*6b7b2d80SAdrian Chadd nct_set_pin_pushpull(struct nct_softc *sc, uint32_t pin_num) 411*6b7b2d80SAdrian Chadd { 412*6b7b2d80SAdrian Chadd uint8_t reg; 413*6b7b2d80SAdrian Chadd uint8_t outcfg; 414*6b7b2d80SAdrian Chadd 415*6b7b2d80SAdrian Chadd reg = nct_outcfg_addr(pin_num); 416*6b7b2d80SAdrian Chadd select_ldn(sc, NCT_LDN_GPIO_MODE); 417*6b7b2d80SAdrian Chadd outcfg = read_cfg_reg_1(sc, reg); 418*6b7b2d80SAdrian Chadd outcfg &= ~(NCT_PIN_BIT(pin_num)); 419*6b7b2d80SAdrian Chadd write_cfg_reg_1(sc, reg, outcfg); 420*6b7b2d80SAdrian Chadd } 421*6b7b2d80SAdrian Chadd 422*6b7b2d80SAdrian Chadd static bool 423*6b7b2d80SAdrian Chadd nct_pin_is_opendrain(struct nct_softc *sc, uint32_t pin_num) 424*6b7b2d80SAdrian Chadd { 425*6b7b2d80SAdrian Chadd uint8_t reg; 426*6b7b2d80SAdrian Chadd uint8_t outcfg; 427*6b7b2d80SAdrian Chadd 428*6b7b2d80SAdrian Chadd reg = nct_outcfg_addr(pin_num); 429*6b7b2d80SAdrian Chadd select_ldn(sc, NCT_LDN_GPIO_MODE); 430*6b7b2d80SAdrian Chadd outcfg = read_cfg_reg_1(sc, reg); 431*6b7b2d80SAdrian Chadd 432*6b7b2d80SAdrian Chadd return (outcfg & NCT_PIN_BIT(pin_num)); 433*6b7b2d80SAdrian Chadd } 434*6b7b2d80SAdrian Chadd 435*6b7b2d80SAdrian Chadd static void 436*6b7b2d80SAdrian Chadd nct_identify(driver_t *driver, device_t parent) 437*6b7b2d80SAdrian Chadd { 438*6b7b2d80SAdrian Chadd if (device_find_child(parent, driver->name, 0) != NULL) 439*6b7b2d80SAdrian Chadd return; 440*6b7b2d80SAdrian Chadd 441*6b7b2d80SAdrian Chadd BUS_ADD_CHILD(parent, 0, driver->name, 0); 442*6b7b2d80SAdrian Chadd } 443*6b7b2d80SAdrian Chadd 444*6b7b2d80SAdrian Chadd static int 445*6b7b2d80SAdrian Chadd nct_probe(device_t dev) 446*6b7b2d80SAdrian Chadd { 447*6b7b2d80SAdrian Chadd int i, j; 448*6b7b2d80SAdrian Chadd int rc; 449*6b7b2d80SAdrian Chadd struct nct_softc *sc; 450*6b7b2d80SAdrian Chadd uint16_t chipid; 451*6b7b2d80SAdrian Chadd 452*6b7b2d80SAdrian Chadd /* Make sure we do not claim some ISA PNP device. */ 453*6b7b2d80SAdrian Chadd if (isa_get_logicalid(dev) != 0) 454*6b7b2d80SAdrian Chadd return (ENXIO); 455*6b7b2d80SAdrian Chadd 456*6b7b2d80SAdrian Chadd sc = device_get_softc(dev); 457*6b7b2d80SAdrian Chadd 458*6b7b2d80SAdrian Chadd for (i = 0; i < sizeof(probe_addrs) / sizeof(*probe_addrs); i++) { 459*6b7b2d80SAdrian Chadd sc->rid = 0; 460*6b7b2d80SAdrian Chadd sc->portres = bus_alloc_resource(dev, SYS_RES_IOPORT, &sc->rid, 461*6b7b2d80SAdrian Chadd probe_addrs[i], probe_addrs[i] + 1, 2, RF_ACTIVE); 462*6b7b2d80SAdrian Chadd if (sc->portres == NULL) 463*6b7b2d80SAdrian Chadd continue; 464*6b7b2d80SAdrian Chadd 465*6b7b2d80SAdrian Chadd GPIO_LOCK_INIT(sc); 466*6b7b2d80SAdrian Chadd 467*6b7b2d80SAdrian Chadd GPIO_ASSERT_UNLOCKED(sc); 468*6b7b2d80SAdrian Chadd GPIO_LOCK(sc); 469*6b7b2d80SAdrian Chadd ext_cfg_enter(sc); 470*6b7b2d80SAdrian Chadd chipid = read_cfg_reg_2(sc, NCT_CR_CHIP_ID); 471*6b7b2d80SAdrian Chadd ext_cfg_exit(sc); 472*6b7b2d80SAdrian Chadd GPIO_UNLOCK(sc); 473*6b7b2d80SAdrian Chadd 474*6b7b2d80SAdrian Chadd GPIO_LOCK_DESTROY(sc); 475*6b7b2d80SAdrian Chadd 476*6b7b2d80SAdrian Chadd bus_release_resource(dev, SYS_RES_IOPORT, sc->rid, sc->portres); 477*6b7b2d80SAdrian Chadd bus_delete_resource(dev, SYS_RES_IOPORT, sc->rid); 478*6b7b2d80SAdrian Chadd 479*6b7b2d80SAdrian Chadd for (j = 0; j < sizeof(nct_devs) / sizeof(*nct_devs); j++) { 480*6b7b2d80SAdrian Chadd if (chipid == nct_devs[j].chip_id) { 481*6b7b2d80SAdrian Chadd rc = bus_set_resource(dev, SYS_RES_IOPORT, 0, probe_addrs[i], 2); 482*6b7b2d80SAdrian Chadd if (rc != 0) { 483*6b7b2d80SAdrian Chadd device_printf(dev, "bus_set_resource failed for address 0x%02X\n", probe_addrs[i]); 484*6b7b2d80SAdrian Chadd continue; 485*6b7b2d80SAdrian Chadd } 486*6b7b2d80SAdrian Chadd device_set_desc(dev, nct_devs[j].descr); 487*6b7b2d80SAdrian Chadd return (BUS_PROBE_DEFAULT); 488*6b7b2d80SAdrian Chadd } 489*6b7b2d80SAdrian Chadd } 490*6b7b2d80SAdrian Chadd } 491*6b7b2d80SAdrian Chadd return (ENXIO); 492*6b7b2d80SAdrian Chadd } 493*6b7b2d80SAdrian Chadd 494*6b7b2d80SAdrian Chadd static int 495*6b7b2d80SAdrian Chadd nct_attach(device_t dev) 496*6b7b2d80SAdrian Chadd { 497*6b7b2d80SAdrian Chadd struct nct_softc *sc; 498*6b7b2d80SAdrian Chadd int i; 499*6b7b2d80SAdrian Chadd 500*6b7b2d80SAdrian Chadd sc = device_get_softc(dev); 501*6b7b2d80SAdrian Chadd 502*6b7b2d80SAdrian Chadd sc->rid = 0; 503*6b7b2d80SAdrian Chadd sc->portres = bus_alloc_resource(dev, SYS_RES_IOPORT, &sc->rid, 504*6b7b2d80SAdrian Chadd 0ul, ~0ul, 2, RF_ACTIVE); 505*6b7b2d80SAdrian Chadd if (sc->portres == NULL) { 506*6b7b2d80SAdrian Chadd device_printf(dev, "cannot allocate ioport\n"); 507*6b7b2d80SAdrian Chadd return (ENXIO); 508*6b7b2d80SAdrian Chadd } 509*6b7b2d80SAdrian Chadd 510*6b7b2d80SAdrian Chadd GPIO_LOCK_INIT(sc); 511*6b7b2d80SAdrian Chadd 512*6b7b2d80SAdrian Chadd GPIO_ASSERT_UNLOCKED(sc); 513*6b7b2d80SAdrian Chadd GPIO_LOCK(sc); 514*6b7b2d80SAdrian Chadd ext_cfg_enter(sc); 515*6b7b2d80SAdrian Chadd select_ldn(sc, NCT_LDN_GPIO); 516*6b7b2d80SAdrian Chadd /* Enable gpio0 and gpio1. */ 517*6b7b2d80SAdrian Chadd write_cfg_reg_1(sc, NCT_LD7_GPIO_ENABLE, 518*6b7b2d80SAdrian Chadd read_cfg_reg_1(sc, NCT_LD7_GPIO_ENABLE) | 0x03); 519*6b7b2d80SAdrian Chadd 520*6b7b2d80SAdrian Chadd for (i = 0; i <= NCT_MAX_PIN; i++) { 521*6b7b2d80SAdrian Chadd struct gpio_pin *pin; 522*6b7b2d80SAdrian Chadd 523*6b7b2d80SAdrian Chadd pin = &sc->pins[i]; 524*6b7b2d80SAdrian Chadd pin->gp_pin = i; 525*6b7b2d80SAdrian Chadd pin->gp_caps = NCT_GPIO_CAPS; 526*6b7b2d80SAdrian Chadd pin->gp_flags = 0; 527*6b7b2d80SAdrian Chadd 528*6b7b2d80SAdrian Chadd snprintf(pin->gp_name, GPIOMAXNAME, "GPIO%02u", i); 529*6b7b2d80SAdrian Chadd pin->gp_name[GPIOMAXNAME - 1] = '\0'; 530*6b7b2d80SAdrian Chadd 531*6b7b2d80SAdrian Chadd if (nct_pin_is_input(sc, i)) 532*6b7b2d80SAdrian Chadd pin->gp_flags |= GPIO_PIN_INPUT; 533*6b7b2d80SAdrian Chadd else 534*6b7b2d80SAdrian Chadd pin->gp_flags |= GPIO_PIN_OUTPUT; 535*6b7b2d80SAdrian Chadd 536*6b7b2d80SAdrian Chadd if (nct_pin_is_opendrain(sc, i)) 537*6b7b2d80SAdrian Chadd pin->gp_flags |= GPIO_PIN_OPENDRAIN; 538*6b7b2d80SAdrian Chadd else 539*6b7b2d80SAdrian Chadd pin->gp_flags |= GPIO_PIN_PUSHPULL; 540*6b7b2d80SAdrian Chadd 541*6b7b2d80SAdrian Chadd if (nct_pin_is_inverted(sc, i)) 542*6b7b2d80SAdrian Chadd pin->gp_flags |= (GPIO_PIN_INVIN | GPIO_PIN_INVOUT); 543*6b7b2d80SAdrian Chadd } 544*6b7b2d80SAdrian Chadd GPIO_UNLOCK(sc); 545*6b7b2d80SAdrian Chadd 546*6b7b2d80SAdrian Chadd sc->busdev = gpiobus_attach_bus(dev); 547*6b7b2d80SAdrian Chadd if (sc->busdev == NULL) { 548*6b7b2d80SAdrian Chadd GPIO_ASSERT_UNLOCKED(sc); 549*6b7b2d80SAdrian Chadd GPIO_LOCK(sc); 550*6b7b2d80SAdrian Chadd ext_cfg_exit(sc); 551*6b7b2d80SAdrian Chadd GPIO_UNLOCK(sc); 552*6b7b2d80SAdrian Chadd bus_release_resource(dev, SYS_RES_IOPORT, sc->rid, sc->portres); 553*6b7b2d80SAdrian Chadd GPIO_LOCK_DESTROY(sc); 554*6b7b2d80SAdrian Chadd 555*6b7b2d80SAdrian Chadd return (ENXIO); 556*6b7b2d80SAdrian Chadd } 557*6b7b2d80SAdrian Chadd 558*6b7b2d80SAdrian Chadd return (0); 559*6b7b2d80SAdrian Chadd } 560*6b7b2d80SAdrian Chadd 561*6b7b2d80SAdrian Chadd static int 562*6b7b2d80SAdrian Chadd nct_detach(device_t dev) 563*6b7b2d80SAdrian Chadd { 564*6b7b2d80SAdrian Chadd struct nct_softc *sc; 565*6b7b2d80SAdrian Chadd 566*6b7b2d80SAdrian Chadd sc = device_get_softc(dev); 567*6b7b2d80SAdrian Chadd gpiobus_detach_bus(dev); 568*6b7b2d80SAdrian Chadd 569*6b7b2d80SAdrian Chadd GPIO_ASSERT_UNLOCKED(sc); 570*6b7b2d80SAdrian Chadd GPIO_LOCK(sc); 571*6b7b2d80SAdrian Chadd ext_cfg_exit(sc); 572*6b7b2d80SAdrian Chadd GPIO_UNLOCK(sc); 573*6b7b2d80SAdrian Chadd 574*6b7b2d80SAdrian Chadd /* Cleanup resources. */ 575*6b7b2d80SAdrian Chadd bus_release_resource(dev, SYS_RES_IOPORT, sc->rid, sc->portres); 576*6b7b2d80SAdrian Chadd 577*6b7b2d80SAdrian Chadd GPIO_LOCK_DESTROY(sc); 578*6b7b2d80SAdrian Chadd 579*6b7b2d80SAdrian Chadd return (0); 580*6b7b2d80SAdrian Chadd } 581*6b7b2d80SAdrian Chadd 582*6b7b2d80SAdrian Chadd static device_t 583*6b7b2d80SAdrian Chadd nct_gpio_get_bus(device_t dev) 584*6b7b2d80SAdrian Chadd { 585*6b7b2d80SAdrian Chadd struct nct_softc *sc; 586*6b7b2d80SAdrian Chadd 587*6b7b2d80SAdrian Chadd sc = device_get_softc(dev); 588*6b7b2d80SAdrian Chadd 589*6b7b2d80SAdrian Chadd return (sc->busdev); 590*6b7b2d80SAdrian Chadd } 591*6b7b2d80SAdrian Chadd 592*6b7b2d80SAdrian Chadd static int 593*6b7b2d80SAdrian Chadd nct_gpio_pin_max(device_t dev, int *npins) 594*6b7b2d80SAdrian Chadd { 595*6b7b2d80SAdrian Chadd *npins = NCT_MAX_PIN; 596*6b7b2d80SAdrian Chadd 597*6b7b2d80SAdrian Chadd return (0); 598*6b7b2d80SAdrian Chadd } 599*6b7b2d80SAdrian Chadd 600*6b7b2d80SAdrian Chadd static int 601*6b7b2d80SAdrian Chadd nct_gpio_pin_set(device_t dev, uint32_t pin_num, uint32_t pin_value) 602*6b7b2d80SAdrian Chadd { 603*6b7b2d80SAdrian Chadd struct nct_softc *sc; 604*6b7b2d80SAdrian Chadd 605*6b7b2d80SAdrian Chadd if (!NCT_IS_VALID_PIN(pin_num)) 606*6b7b2d80SAdrian Chadd return (EINVAL); 607*6b7b2d80SAdrian Chadd 608*6b7b2d80SAdrian Chadd sc = device_get_softc(dev); 609*6b7b2d80SAdrian Chadd GPIO_ASSERT_UNLOCKED(sc); 610*6b7b2d80SAdrian Chadd GPIO_LOCK(sc); 611*6b7b2d80SAdrian Chadd nct_write_pin(sc, pin_num, pin_value); 612*6b7b2d80SAdrian Chadd GPIO_UNLOCK(sc); 613*6b7b2d80SAdrian Chadd 614*6b7b2d80SAdrian Chadd return (0); 615*6b7b2d80SAdrian Chadd } 616*6b7b2d80SAdrian Chadd 617*6b7b2d80SAdrian Chadd static int 618*6b7b2d80SAdrian Chadd nct_gpio_pin_get(device_t dev, uint32_t pin_num, uint32_t *pin_value) 619*6b7b2d80SAdrian Chadd { 620*6b7b2d80SAdrian Chadd struct nct_softc *sc; 621*6b7b2d80SAdrian Chadd 622*6b7b2d80SAdrian Chadd if (!NCT_IS_VALID_PIN(pin_num)) 623*6b7b2d80SAdrian Chadd return (EINVAL); 624*6b7b2d80SAdrian Chadd 625*6b7b2d80SAdrian Chadd sc = device_get_softc(dev); 626*6b7b2d80SAdrian Chadd GPIO_ASSERT_UNLOCKED(sc); 627*6b7b2d80SAdrian Chadd GPIO_LOCK(sc); 628*6b7b2d80SAdrian Chadd *pin_value = nct_read_pin(sc, pin_num); 629*6b7b2d80SAdrian Chadd GPIO_UNLOCK(sc); 630*6b7b2d80SAdrian Chadd 631*6b7b2d80SAdrian Chadd return (0); 632*6b7b2d80SAdrian Chadd } 633*6b7b2d80SAdrian Chadd 634*6b7b2d80SAdrian Chadd static int 635*6b7b2d80SAdrian Chadd nct_gpio_pin_toggle(device_t dev, uint32_t pin_num) 636*6b7b2d80SAdrian Chadd { 637*6b7b2d80SAdrian Chadd struct nct_softc *sc; 638*6b7b2d80SAdrian Chadd 639*6b7b2d80SAdrian Chadd if (!NCT_IS_VALID_PIN(pin_num)) 640*6b7b2d80SAdrian Chadd return (EINVAL); 641*6b7b2d80SAdrian Chadd 642*6b7b2d80SAdrian Chadd sc = device_get_softc(dev); 643*6b7b2d80SAdrian Chadd GPIO_ASSERT_UNLOCKED(sc); 644*6b7b2d80SAdrian Chadd GPIO_LOCK(sc); 645*6b7b2d80SAdrian Chadd if (nct_read_pin(sc, pin_num)) 646*6b7b2d80SAdrian Chadd nct_write_pin(sc, pin_num, 0); 647*6b7b2d80SAdrian Chadd else 648*6b7b2d80SAdrian Chadd nct_write_pin(sc, pin_num, 1); 649*6b7b2d80SAdrian Chadd 650*6b7b2d80SAdrian Chadd GPIO_UNLOCK(sc); 651*6b7b2d80SAdrian Chadd 652*6b7b2d80SAdrian Chadd return (0); 653*6b7b2d80SAdrian Chadd } 654*6b7b2d80SAdrian Chadd 655*6b7b2d80SAdrian Chadd static int 656*6b7b2d80SAdrian Chadd nct_gpio_pin_getcaps(device_t dev, uint32_t pin_num, uint32_t *caps) 657*6b7b2d80SAdrian Chadd { 658*6b7b2d80SAdrian Chadd struct nct_softc *sc; 659*6b7b2d80SAdrian Chadd 660*6b7b2d80SAdrian Chadd if (!NCT_IS_VALID_PIN(pin_num)) 661*6b7b2d80SAdrian Chadd return (EINVAL); 662*6b7b2d80SAdrian Chadd 663*6b7b2d80SAdrian Chadd sc = device_get_softc(dev); 664*6b7b2d80SAdrian Chadd GPIO_ASSERT_UNLOCKED(sc); 665*6b7b2d80SAdrian Chadd GPIO_LOCK(sc); 666*6b7b2d80SAdrian Chadd *caps = sc->pins[pin_num].gp_caps; 667*6b7b2d80SAdrian Chadd GPIO_UNLOCK(sc); 668*6b7b2d80SAdrian Chadd 669*6b7b2d80SAdrian Chadd return (0); 670*6b7b2d80SAdrian Chadd } 671*6b7b2d80SAdrian Chadd 672*6b7b2d80SAdrian Chadd static int 673*6b7b2d80SAdrian Chadd nct_gpio_pin_getflags(device_t dev, uint32_t pin_num, uint32_t *flags) 674*6b7b2d80SAdrian Chadd { 675*6b7b2d80SAdrian Chadd struct nct_softc *sc; 676*6b7b2d80SAdrian Chadd 677*6b7b2d80SAdrian Chadd if (!NCT_IS_VALID_PIN(pin_num)) 678*6b7b2d80SAdrian Chadd return (EINVAL); 679*6b7b2d80SAdrian Chadd 680*6b7b2d80SAdrian Chadd sc = device_get_softc(dev); 681*6b7b2d80SAdrian Chadd GPIO_ASSERT_UNLOCKED(sc); 682*6b7b2d80SAdrian Chadd GPIO_LOCK(sc); 683*6b7b2d80SAdrian Chadd *flags = sc->pins[pin_num].gp_flags; 684*6b7b2d80SAdrian Chadd GPIO_UNLOCK(sc); 685*6b7b2d80SAdrian Chadd 686*6b7b2d80SAdrian Chadd return (0); 687*6b7b2d80SAdrian Chadd } 688*6b7b2d80SAdrian Chadd 689*6b7b2d80SAdrian Chadd static int 690*6b7b2d80SAdrian Chadd nct_gpio_pin_getname(device_t dev, uint32_t pin_num, char *name) 691*6b7b2d80SAdrian Chadd { 692*6b7b2d80SAdrian Chadd struct nct_softc *sc; 693*6b7b2d80SAdrian Chadd 694*6b7b2d80SAdrian Chadd if (!NCT_IS_VALID_PIN(pin_num)) 695*6b7b2d80SAdrian Chadd return (EINVAL); 696*6b7b2d80SAdrian Chadd 697*6b7b2d80SAdrian Chadd sc = device_get_softc(dev); 698*6b7b2d80SAdrian Chadd GPIO_ASSERT_UNLOCKED(sc); 699*6b7b2d80SAdrian Chadd GPIO_LOCK(sc); 700*6b7b2d80SAdrian Chadd memcpy(name, sc->pins[pin_num].gp_name, GPIOMAXNAME); 701*6b7b2d80SAdrian Chadd GPIO_UNLOCK(sc); 702*6b7b2d80SAdrian Chadd 703*6b7b2d80SAdrian Chadd return (0); 704*6b7b2d80SAdrian Chadd } 705*6b7b2d80SAdrian Chadd 706*6b7b2d80SAdrian Chadd static int 707*6b7b2d80SAdrian Chadd nct_gpio_pin_setflags(device_t dev, uint32_t pin_num, uint32_t flags) 708*6b7b2d80SAdrian Chadd { 709*6b7b2d80SAdrian Chadd struct nct_softc *sc; 710*6b7b2d80SAdrian Chadd struct gpio_pin *pin; 711*6b7b2d80SAdrian Chadd 712*6b7b2d80SAdrian Chadd if (!NCT_IS_VALID_PIN(pin_num)) 713*6b7b2d80SAdrian Chadd return (EINVAL); 714*6b7b2d80SAdrian Chadd 715*6b7b2d80SAdrian Chadd sc = device_get_softc(dev); 716*6b7b2d80SAdrian Chadd pin = &sc->pins[pin_num]; 717*6b7b2d80SAdrian Chadd if ((flags & pin->gp_caps) != flags) 718*6b7b2d80SAdrian Chadd return (EINVAL); 719*6b7b2d80SAdrian Chadd 720*6b7b2d80SAdrian Chadd GPIO_ASSERT_UNLOCKED(sc); 721*6b7b2d80SAdrian Chadd GPIO_LOCK(sc); 722*6b7b2d80SAdrian Chadd if (flags & (GPIO_PIN_INPUT | GPIO_PIN_OUTPUT)) { 723*6b7b2d80SAdrian Chadd if ((flags & (GPIO_PIN_INPUT | GPIO_PIN_OUTPUT)) == 724*6b7b2d80SAdrian Chadd (GPIO_PIN_INPUT | GPIO_PIN_OUTPUT)) { 725*6b7b2d80SAdrian Chadd GPIO_UNLOCK(sc); 726*6b7b2d80SAdrian Chadd return (EINVAL); 727*6b7b2d80SAdrian Chadd } 728*6b7b2d80SAdrian Chadd 729*6b7b2d80SAdrian Chadd if (flags & GPIO_PIN_INPUT) 730*6b7b2d80SAdrian Chadd nct_set_pin_is_input(sc, pin_num); 731*6b7b2d80SAdrian Chadd else 732*6b7b2d80SAdrian Chadd nct_set_pin_is_output(sc, pin_num); 733*6b7b2d80SAdrian Chadd } 734*6b7b2d80SAdrian Chadd 735*6b7b2d80SAdrian Chadd if (flags & (GPIO_PIN_OPENDRAIN | GPIO_PIN_PUSHPULL)) { 736*6b7b2d80SAdrian Chadd if (flags & GPIO_PIN_INPUT) { 737*6b7b2d80SAdrian Chadd GPIO_UNLOCK(sc); 738*6b7b2d80SAdrian Chadd return (EINVAL); 739*6b7b2d80SAdrian Chadd } 740*6b7b2d80SAdrian Chadd 741*6b7b2d80SAdrian Chadd if ((flags & (GPIO_PIN_OPENDRAIN | GPIO_PIN_PUSHPULL)) == 742*6b7b2d80SAdrian Chadd (GPIO_PIN_OPENDRAIN | GPIO_PIN_PUSHPULL)) { 743*6b7b2d80SAdrian Chadd GPIO_UNLOCK(sc); 744*6b7b2d80SAdrian Chadd return (EINVAL); 745*6b7b2d80SAdrian Chadd } 746*6b7b2d80SAdrian Chadd 747*6b7b2d80SAdrian Chadd if (flags & GPIO_PIN_OPENDRAIN) 748*6b7b2d80SAdrian Chadd nct_set_pin_opendrain(sc, pin_num); 749*6b7b2d80SAdrian Chadd else 750*6b7b2d80SAdrian Chadd nct_set_pin_pushpull(sc, pin_num); 751*6b7b2d80SAdrian Chadd } 752*6b7b2d80SAdrian Chadd 753*6b7b2d80SAdrian Chadd if (flags & (GPIO_PIN_INVIN | GPIO_PIN_INVOUT)) { 754*6b7b2d80SAdrian Chadd if ((flags & (GPIO_PIN_INVIN | GPIO_PIN_INVOUT)) != 755*6b7b2d80SAdrian Chadd (GPIO_PIN_INVIN | GPIO_PIN_INVOUT)) { 756*6b7b2d80SAdrian Chadd GPIO_UNLOCK(sc); 757*6b7b2d80SAdrian Chadd return (EINVAL); 758*6b7b2d80SAdrian Chadd } 759*6b7b2d80SAdrian Chadd 760*6b7b2d80SAdrian Chadd if (flags & GPIO_PIN_INVIN) 761*6b7b2d80SAdrian Chadd nct_set_pin_is_inverted(sc, pin_num); 762*6b7b2d80SAdrian Chadd else 763*6b7b2d80SAdrian Chadd nct_set_pin_not_inverted(sc, pin_num); 764*6b7b2d80SAdrian Chadd } 765*6b7b2d80SAdrian Chadd 766*6b7b2d80SAdrian Chadd pin->gp_flags = flags; 767*6b7b2d80SAdrian Chadd GPIO_UNLOCK(sc); 768*6b7b2d80SAdrian Chadd 769*6b7b2d80SAdrian Chadd return (0); 770*6b7b2d80SAdrian Chadd } 771*6b7b2d80SAdrian Chadd 772*6b7b2d80SAdrian Chadd static device_method_t nct_methods[] = { 773*6b7b2d80SAdrian Chadd /* Device interface */ 774*6b7b2d80SAdrian Chadd DEVMETHOD(device_identify, nct_identify), 775*6b7b2d80SAdrian Chadd DEVMETHOD(device_probe, nct_probe), 776*6b7b2d80SAdrian Chadd DEVMETHOD(device_attach, nct_attach), 777*6b7b2d80SAdrian Chadd DEVMETHOD(device_detach, nct_detach), 778*6b7b2d80SAdrian Chadd 779*6b7b2d80SAdrian Chadd /* GPIO */ 780*6b7b2d80SAdrian Chadd DEVMETHOD(gpio_get_bus, nct_gpio_get_bus), 781*6b7b2d80SAdrian Chadd DEVMETHOD(gpio_pin_max, nct_gpio_pin_max), 782*6b7b2d80SAdrian Chadd DEVMETHOD(gpio_pin_get, nct_gpio_pin_get), 783*6b7b2d80SAdrian Chadd DEVMETHOD(gpio_pin_set, nct_gpio_pin_set), 784*6b7b2d80SAdrian Chadd DEVMETHOD(gpio_pin_toggle, nct_gpio_pin_toggle), 785*6b7b2d80SAdrian Chadd DEVMETHOD(gpio_pin_getname, nct_gpio_pin_getname), 786*6b7b2d80SAdrian Chadd DEVMETHOD(gpio_pin_getcaps, nct_gpio_pin_getcaps), 787*6b7b2d80SAdrian Chadd DEVMETHOD(gpio_pin_getflags, nct_gpio_pin_getflags), 788*6b7b2d80SAdrian Chadd DEVMETHOD(gpio_pin_setflags, nct_gpio_pin_setflags), 789*6b7b2d80SAdrian Chadd 790*6b7b2d80SAdrian Chadd DEVMETHOD_END 791*6b7b2d80SAdrian Chadd }; 792*6b7b2d80SAdrian Chadd 793*6b7b2d80SAdrian Chadd static driver_t nct_isa_driver = { 794*6b7b2d80SAdrian Chadd "gpio", 795*6b7b2d80SAdrian Chadd nct_methods, 796*6b7b2d80SAdrian Chadd sizeof(struct nct_softc) 797*6b7b2d80SAdrian Chadd }; 798*6b7b2d80SAdrian Chadd 799*6b7b2d80SAdrian Chadd static devclass_t nct_devclass; 800*6b7b2d80SAdrian Chadd 801*6b7b2d80SAdrian Chadd DRIVER_MODULE(nctgpio, isa, nct_isa_driver, nct_devclass, NULL, NULL); 802*6b7b2d80SAdrian Chadd MODULE_DEPEND(nctgpio, gpiobus, 1, 1, 1); 803