1*a0d65009SMaciej S. Szmigiero // SPDX-License-Identifier: GPL-2.0+ 2*a0d65009SMaciej S. Szmigiero /* 3*a0d65009SMaciej S. Szmigiero * GPIO interface for Winbond Super I/O chips 4*a0d65009SMaciej S. Szmigiero * Currently, only W83627UHG (Nuvoton NCT6627UD) is supported. 5*a0d65009SMaciej S. Szmigiero * 6*a0d65009SMaciej S. Szmigiero * Author: Maciej S. Szmigiero <mail@maciej.szmigiero.name> 7*a0d65009SMaciej S. Szmigiero */ 8*a0d65009SMaciej S. Szmigiero 9*a0d65009SMaciej S. Szmigiero #define pr_fmt(fmt) KBUILD_MODNAME ": " fmt 10*a0d65009SMaciej S. Szmigiero 11*a0d65009SMaciej S. Szmigiero #include <linux/gpio/driver.h> 12*a0d65009SMaciej S. Szmigiero #include <linux/ioport.h> 13*a0d65009SMaciej S. Szmigiero #include <linux/isa.h> 14*a0d65009SMaciej S. Szmigiero #include <linux/module.h> 15*a0d65009SMaciej S. Szmigiero 16*a0d65009SMaciej S. Szmigiero #define WB_GPIO_DRIVER_NAME KBUILD_MODNAME 17*a0d65009SMaciej S. Szmigiero 18*a0d65009SMaciej S. Szmigiero #define WB_SIO_BASE 0x2e 19*a0d65009SMaciej S. Szmigiero #define WB_SIO_BASE_HIGH 0x4e 20*a0d65009SMaciej S. Szmigiero 21*a0d65009SMaciej S. Szmigiero #define WB_SIO_EXT_ENTER_KEY 0x87 22*a0d65009SMaciej S. Szmigiero #define WB_SIO_EXT_EXIT_KEY 0xaa 23*a0d65009SMaciej S. Szmigiero 24*a0d65009SMaciej S. Szmigiero /* global chip registers */ 25*a0d65009SMaciej S. Szmigiero 26*a0d65009SMaciej S. Szmigiero #define WB_SIO_REG_LOGICAL 0x07 27*a0d65009SMaciej S. Szmigiero 28*a0d65009SMaciej S. Szmigiero #define WB_SIO_REG_CHIP_MSB 0x20 29*a0d65009SMaciej S. Szmigiero #define WB_SIO_REG_CHIP_LSB 0x21 30*a0d65009SMaciej S. Szmigiero 31*a0d65009SMaciej S. Szmigiero #define WB_SIO_CHIP_ID_W83627UHG 0xa230 32*a0d65009SMaciej S. Szmigiero #define WB_SIO_CHIP_ID_W83627UHG_MASK GENMASK(15, 4) 33*a0d65009SMaciej S. Szmigiero 34*a0d65009SMaciej S. Szmigiero #define WB_SIO_REG_DPD 0x22 35*a0d65009SMaciej S. Szmigiero #define WB_SIO_REG_DPD_UARTA 4 36*a0d65009SMaciej S. Szmigiero #define WB_SIO_REG_DPD_UARTB 5 37*a0d65009SMaciej S. Szmigiero 38*a0d65009SMaciej S. Szmigiero #define WB_SIO_REG_IDPD 0x23 39*a0d65009SMaciej S. Szmigiero #define WB_SIO_REG_IDPD_UARTC 4 40*a0d65009SMaciej S. Szmigiero #define WB_SIO_REG_IDPD_UARTD 5 41*a0d65009SMaciej S. Szmigiero #define WB_SIO_REG_IDPD_UARTE 6 42*a0d65009SMaciej S. Szmigiero #define WB_SIO_REG_IDPD_UARTF 7 43*a0d65009SMaciej S. Szmigiero 44*a0d65009SMaciej S. Szmigiero #define WB_SIO_REG_GLOBAL_OPT 0x24 45*a0d65009SMaciej S. Szmigiero #define WB_SIO_REG_GO_ENFDC 1 46*a0d65009SMaciej S. Szmigiero 47*a0d65009SMaciej S. Szmigiero #define WB_SIO_REG_OVTGPIO3456 0x29 48*a0d65009SMaciej S. Szmigiero #define WB_SIO_REG_OG3456_G3PP 3 49*a0d65009SMaciej S. Szmigiero #define WB_SIO_REG_OG3456_G4PP 4 50*a0d65009SMaciej S. Szmigiero #define WB_SIO_REG_OG3456_G5PP 5 51*a0d65009SMaciej S. Szmigiero #define WB_SIO_REG_OG3456_G6PP 7 52*a0d65009SMaciej S. Szmigiero 53*a0d65009SMaciej S. Szmigiero #define WB_SIO_REG_I2C_PS 0x2a 54*a0d65009SMaciej S. Szmigiero #define WB_SIO_REG_I2CPS_I2CFS 1 55*a0d65009SMaciej S. Szmigiero 56*a0d65009SMaciej S. Szmigiero #define WB_SIO_REG_GPIO1_MF 0x2c 57*a0d65009SMaciej S. Szmigiero #define WB_SIO_REG_G1MF_G1PP 6 58*a0d65009SMaciej S. Szmigiero #define WB_SIO_REG_G1MF_G2PP 7 59*a0d65009SMaciej S. Szmigiero #define WB_SIO_REG_G1MF_FS_MASK GENMASK(1, 0) 60*a0d65009SMaciej S. Szmigiero #define WB_SIO_REG_G1MF_FS_IR_OFF 0 61*a0d65009SMaciej S. Szmigiero #define WB_SIO_REG_G1MF_FS_IR 1 62*a0d65009SMaciej S. Szmigiero #define WB_SIO_REG_G1MF_FS_GPIO1 2 63*a0d65009SMaciej S. Szmigiero #define WB_SIO_REG_G1MF_FS_UARTB 3 64*a0d65009SMaciej S. Szmigiero 65*a0d65009SMaciej S. Szmigiero /* not an actual device number, just a value meaning 'no device' */ 66*a0d65009SMaciej S. Szmigiero #define WB_SIO_DEV_NONE 0xff 67*a0d65009SMaciej S. Szmigiero 68*a0d65009SMaciej S. Szmigiero /* registers with offsets >= 0x30 are specific for a particular device */ 69*a0d65009SMaciej S. Szmigiero 70*a0d65009SMaciej S. Szmigiero /* UART B logical device */ 71*a0d65009SMaciej S. Szmigiero #define WB_SIO_DEV_UARTB 0x03 72*a0d65009SMaciej S. Szmigiero #define WB_SIO_UARTB_REG_ENABLE 0x30 73*a0d65009SMaciej S. Szmigiero #define WB_SIO_UARTB_ENABLE_ON 0 74*a0d65009SMaciej S. Szmigiero 75*a0d65009SMaciej S. Szmigiero /* UART C logical device */ 76*a0d65009SMaciej S. Szmigiero #define WB_SIO_DEV_UARTC 0x06 77*a0d65009SMaciej S. Szmigiero #define WB_SIO_UARTC_REG_ENABLE 0x30 78*a0d65009SMaciej S. Szmigiero #define WB_SIO_UARTC_ENABLE_ON 0 79*a0d65009SMaciej S. Szmigiero 80*a0d65009SMaciej S. Szmigiero /* GPIO3, GPIO4 logical device */ 81*a0d65009SMaciej S. Szmigiero #define WB_SIO_DEV_GPIO34 0x07 82*a0d65009SMaciej S. Szmigiero #define WB_SIO_GPIO34_REG_ENABLE 0x30 83*a0d65009SMaciej S. Szmigiero #define WB_SIO_GPIO34_ENABLE_3 0 84*a0d65009SMaciej S. Szmigiero #define WB_SIO_GPIO34_ENABLE_4 1 85*a0d65009SMaciej S. Szmigiero #define WB_SIO_GPIO34_REG_IO3 0xe0 86*a0d65009SMaciej S. Szmigiero #define WB_SIO_GPIO34_REG_DATA3 0xe1 87*a0d65009SMaciej S. Szmigiero #define WB_SIO_GPIO34_REG_INV3 0xe2 88*a0d65009SMaciej S. Szmigiero #define WB_SIO_GPIO34_REG_IO4 0xe4 89*a0d65009SMaciej S. Szmigiero #define WB_SIO_GPIO34_REG_DATA4 0xe5 90*a0d65009SMaciej S. Szmigiero #define WB_SIO_GPIO34_REG_INV4 0xe6 91*a0d65009SMaciej S. Szmigiero 92*a0d65009SMaciej S. Szmigiero /* WDTO, PLED, GPIO5, GPIO6 logical device */ 93*a0d65009SMaciej S. Szmigiero #define WB_SIO_DEV_WDGPIO56 0x08 94*a0d65009SMaciej S. Szmigiero #define WB_SIO_WDGPIO56_REG_ENABLE 0x30 95*a0d65009SMaciej S. Szmigiero #define WB_SIO_WDGPIO56_ENABLE_5 1 96*a0d65009SMaciej S. Szmigiero #define WB_SIO_WDGPIO56_ENABLE_6 2 97*a0d65009SMaciej S. Szmigiero #define WB_SIO_WDGPIO56_REG_IO5 0xe0 98*a0d65009SMaciej S. Szmigiero #define WB_SIO_WDGPIO56_REG_DATA5 0xe1 99*a0d65009SMaciej S. Szmigiero #define WB_SIO_WDGPIO56_REG_INV5 0xe2 100*a0d65009SMaciej S. Szmigiero #define WB_SIO_WDGPIO56_REG_IO6 0xe4 101*a0d65009SMaciej S. Szmigiero #define WB_SIO_WDGPIO56_REG_DATA6 0xe5 102*a0d65009SMaciej S. Szmigiero #define WB_SIO_WDGPIO56_REG_INV6 0xe6 103*a0d65009SMaciej S. Szmigiero 104*a0d65009SMaciej S. Szmigiero /* GPIO1, GPIO2, SUSLED logical device */ 105*a0d65009SMaciej S. Szmigiero #define WB_SIO_DEV_GPIO12 0x09 106*a0d65009SMaciej S. Szmigiero #define WB_SIO_GPIO12_REG_ENABLE 0x30 107*a0d65009SMaciej S. Szmigiero #define WB_SIO_GPIO12_ENABLE_1 0 108*a0d65009SMaciej S. Szmigiero #define WB_SIO_GPIO12_ENABLE_2 1 109*a0d65009SMaciej S. Szmigiero #define WB_SIO_GPIO12_REG_IO1 0xe0 110*a0d65009SMaciej S. Szmigiero #define WB_SIO_GPIO12_REG_DATA1 0xe1 111*a0d65009SMaciej S. Szmigiero #define WB_SIO_GPIO12_REG_INV1 0xe2 112*a0d65009SMaciej S. Szmigiero #define WB_SIO_GPIO12_REG_IO2 0xe4 113*a0d65009SMaciej S. Szmigiero #define WB_SIO_GPIO12_REG_DATA2 0xe5 114*a0d65009SMaciej S. Szmigiero #define WB_SIO_GPIO12_REG_INV2 0xe6 115*a0d65009SMaciej S. Szmigiero 116*a0d65009SMaciej S. Szmigiero /* UART D logical device */ 117*a0d65009SMaciej S. Szmigiero #define WB_SIO_DEV_UARTD 0x0d 118*a0d65009SMaciej S. Szmigiero #define WB_SIO_UARTD_REG_ENABLE 0x30 119*a0d65009SMaciej S. Szmigiero #define WB_SIO_UARTD_ENABLE_ON 0 120*a0d65009SMaciej S. Szmigiero 121*a0d65009SMaciej S. Szmigiero /* UART E logical device */ 122*a0d65009SMaciej S. Szmigiero #define WB_SIO_DEV_UARTE 0x0e 123*a0d65009SMaciej S. Szmigiero #define WB_SIO_UARTE_REG_ENABLE 0x30 124*a0d65009SMaciej S. Szmigiero #define WB_SIO_UARTE_ENABLE_ON 0 125*a0d65009SMaciej S. Szmigiero 126*a0d65009SMaciej S. Szmigiero /* 127*a0d65009SMaciej S. Szmigiero * for a description what a particular field of this struct means please see 128*a0d65009SMaciej S. Szmigiero * a description of the relevant module parameter at the bottom of this file 129*a0d65009SMaciej S. Szmigiero */ 130*a0d65009SMaciej S. Szmigiero struct winbond_gpio_params { 131*a0d65009SMaciej S. Szmigiero unsigned long base; 132*a0d65009SMaciej S. Szmigiero unsigned long gpios; 133*a0d65009SMaciej S. Szmigiero unsigned long ppgpios; 134*a0d65009SMaciej S. Szmigiero unsigned long odgpios; 135*a0d65009SMaciej S. Szmigiero bool pledgpio; 136*a0d65009SMaciej S. Szmigiero bool beepgpio; 137*a0d65009SMaciej S. Szmigiero bool i2cgpio; 138*a0d65009SMaciej S. Szmigiero }; 139*a0d65009SMaciej S. Szmigiero 140*a0d65009SMaciej S. Szmigiero static struct winbond_gpio_params params; 141*a0d65009SMaciej S. Szmigiero 142*a0d65009SMaciej S. Szmigiero static int winbond_sio_enter(unsigned long base) 143*a0d65009SMaciej S. Szmigiero { 144*a0d65009SMaciej S. Szmigiero if (!request_muxed_region(base, 2, WB_GPIO_DRIVER_NAME)) 145*a0d65009SMaciej S. Szmigiero return -EBUSY; 146*a0d65009SMaciej S. Szmigiero 147*a0d65009SMaciej S. Szmigiero /* 148*a0d65009SMaciej S. Szmigiero * datasheet says two successive writes of the "key" value are needed 149*a0d65009SMaciej S. Szmigiero * in order for chip to enter the "Extended Function Mode" 150*a0d65009SMaciej S. Szmigiero */ 151*a0d65009SMaciej S. Szmigiero outb(WB_SIO_EXT_ENTER_KEY, base); 152*a0d65009SMaciej S. Szmigiero outb(WB_SIO_EXT_ENTER_KEY, base); 153*a0d65009SMaciej S. Szmigiero 154*a0d65009SMaciej S. Szmigiero return 0; 155*a0d65009SMaciej S. Szmigiero } 156*a0d65009SMaciej S. Szmigiero 157*a0d65009SMaciej S. Szmigiero static void winbond_sio_select_logical(unsigned long base, u8 dev) 158*a0d65009SMaciej S. Szmigiero { 159*a0d65009SMaciej S. Szmigiero outb(WB_SIO_REG_LOGICAL, base); 160*a0d65009SMaciej S. Szmigiero outb(dev, base + 1); 161*a0d65009SMaciej S. Szmigiero } 162*a0d65009SMaciej S. Szmigiero 163*a0d65009SMaciej S. Szmigiero static void winbond_sio_leave(unsigned long base) 164*a0d65009SMaciej S. Szmigiero { 165*a0d65009SMaciej S. Szmigiero outb(WB_SIO_EXT_EXIT_KEY, base); 166*a0d65009SMaciej S. Szmigiero 167*a0d65009SMaciej S. Szmigiero release_region(base, 2); 168*a0d65009SMaciej S. Szmigiero } 169*a0d65009SMaciej S. Szmigiero 170*a0d65009SMaciej S. Szmigiero static void winbond_sio_reg_write(unsigned long base, u8 reg, u8 data) 171*a0d65009SMaciej S. Szmigiero { 172*a0d65009SMaciej S. Szmigiero outb(reg, base); 173*a0d65009SMaciej S. Szmigiero outb(data, base + 1); 174*a0d65009SMaciej S. Szmigiero } 175*a0d65009SMaciej S. Szmigiero 176*a0d65009SMaciej S. Szmigiero static u8 winbond_sio_reg_read(unsigned long base, u8 reg) 177*a0d65009SMaciej S. Szmigiero { 178*a0d65009SMaciej S. Szmigiero outb(reg, base); 179*a0d65009SMaciej S. Szmigiero return inb(base + 1); 180*a0d65009SMaciej S. Szmigiero } 181*a0d65009SMaciej S. Szmigiero 182*a0d65009SMaciej S. Szmigiero static void winbond_sio_reg_bset(unsigned long base, u8 reg, u8 bit) 183*a0d65009SMaciej S. Szmigiero { 184*a0d65009SMaciej S. Szmigiero u8 val; 185*a0d65009SMaciej S. Szmigiero 186*a0d65009SMaciej S. Szmigiero val = winbond_sio_reg_read(base, reg); 187*a0d65009SMaciej S. Szmigiero val |= BIT(bit); 188*a0d65009SMaciej S. Szmigiero winbond_sio_reg_write(base, reg, val); 189*a0d65009SMaciej S. Szmigiero } 190*a0d65009SMaciej S. Szmigiero 191*a0d65009SMaciej S. Szmigiero static void winbond_sio_reg_bclear(unsigned long base, u8 reg, u8 bit) 192*a0d65009SMaciej S. Szmigiero { 193*a0d65009SMaciej S. Szmigiero u8 val; 194*a0d65009SMaciej S. Szmigiero 195*a0d65009SMaciej S. Szmigiero val = winbond_sio_reg_read(base, reg); 196*a0d65009SMaciej S. Szmigiero val &= ~BIT(bit); 197*a0d65009SMaciej S. Szmigiero winbond_sio_reg_write(base, reg, val); 198*a0d65009SMaciej S. Szmigiero } 199*a0d65009SMaciej S. Szmigiero 200*a0d65009SMaciej S. Szmigiero static bool winbond_sio_reg_btest(unsigned long base, u8 reg, u8 bit) 201*a0d65009SMaciej S. Szmigiero { 202*a0d65009SMaciej S. Szmigiero return winbond_sio_reg_read(base, reg) & BIT(bit); 203*a0d65009SMaciej S. Szmigiero } 204*a0d65009SMaciej S. Szmigiero 205*a0d65009SMaciej S. Szmigiero /** 206*a0d65009SMaciej S. Szmigiero * struct winbond_gpio_port_conflict - possibly conflicting device information 207*a0d65009SMaciej S. Szmigiero * @name: device name (NULL means no conflicting device defined) 208*a0d65009SMaciej S. Szmigiero * @dev: Super I/O logical device number where the testreg register 209*a0d65009SMaciej S. Szmigiero * is located (or WB_SIO_DEV_NONE - don't select any 210*a0d65009SMaciej S. Szmigiero * logical device) 211*a0d65009SMaciej S. Szmigiero * @testreg: register number where the testbit bit is located 212*a0d65009SMaciej S. Szmigiero * @testbit: index of a bit to check whether an actual conflict exists 213*a0d65009SMaciej S. Szmigiero * @warnonly: if set then a conflict isn't fatal (just warn about it), 214*a0d65009SMaciej S. Szmigiero * otherwise disable the particular GPIO port if a conflict 215*a0d65009SMaciej S. Szmigiero * is detected 216*a0d65009SMaciej S. Szmigiero */ 217*a0d65009SMaciej S. Szmigiero struct winbond_gpio_port_conflict { 218*a0d65009SMaciej S. Szmigiero const char *name; 219*a0d65009SMaciej S. Szmigiero u8 dev; 220*a0d65009SMaciej S. Szmigiero u8 testreg; 221*a0d65009SMaciej S. Szmigiero u8 testbit; 222*a0d65009SMaciej S. Szmigiero bool warnonly; 223*a0d65009SMaciej S. Szmigiero }; 224*a0d65009SMaciej S. Szmigiero 225*a0d65009SMaciej S. Szmigiero /** 226*a0d65009SMaciej S. Szmigiero * struct winbond_gpio_info - information about a particular GPIO port (device) 227*a0d65009SMaciej S. Szmigiero * @dev: Super I/O logical device number of the registers 228*a0d65009SMaciej S. Szmigiero * specified below 229*a0d65009SMaciej S. Szmigiero * @enablereg: port enable bit register number 230*a0d65009SMaciej S. Szmigiero * @enablebit: index of a port enable bit 231*a0d65009SMaciej S. Szmigiero * @outputreg: output driver mode bit register number 232*a0d65009SMaciej S. Szmigiero * @outputppbit: index of a push-pull output driver mode bit 233*a0d65009SMaciej S. Szmigiero * @ioreg: data direction register number 234*a0d65009SMaciej S. Szmigiero * @invreg: pin data inversion register number 235*a0d65009SMaciej S. Szmigiero * @datareg: pin data register number 236*a0d65009SMaciej S. Szmigiero * @conflict: description of a device that possibly conflicts with 237*a0d65009SMaciej S. Szmigiero * this port 238*a0d65009SMaciej S. Szmigiero */ 239*a0d65009SMaciej S. Szmigiero struct winbond_gpio_info { 240*a0d65009SMaciej S. Szmigiero u8 dev; 241*a0d65009SMaciej S. Szmigiero u8 enablereg; 242*a0d65009SMaciej S. Szmigiero u8 enablebit; 243*a0d65009SMaciej S. Szmigiero u8 outputreg; 244*a0d65009SMaciej S. Szmigiero u8 outputppbit; 245*a0d65009SMaciej S. Szmigiero u8 ioreg; 246*a0d65009SMaciej S. Szmigiero u8 invreg; 247*a0d65009SMaciej S. Szmigiero u8 datareg; 248*a0d65009SMaciej S. Szmigiero struct winbond_gpio_port_conflict conflict; 249*a0d65009SMaciej S. Szmigiero }; 250*a0d65009SMaciej S. Szmigiero 251*a0d65009SMaciej S. Szmigiero static const struct winbond_gpio_info winbond_gpio_infos[6] = { 252*a0d65009SMaciej S. Szmigiero { /* 0 */ 253*a0d65009SMaciej S. Szmigiero .dev = WB_SIO_DEV_GPIO12, 254*a0d65009SMaciej S. Szmigiero .enablereg = WB_SIO_GPIO12_REG_ENABLE, 255*a0d65009SMaciej S. Szmigiero .enablebit = WB_SIO_GPIO12_ENABLE_1, 256*a0d65009SMaciej S. Szmigiero .outputreg = WB_SIO_REG_GPIO1_MF, 257*a0d65009SMaciej S. Szmigiero .outputppbit = WB_SIO_REG_G1MF_G1PP, 258*a0d65009SMaciej S. Szmigiero .ioreg = WB_SIO_GPIO12_REG_IO1, 259*a0d65009SMaciej S. Szmigiero .invreg = WB_SIO_GPIO12_REG_INV1, 260*a0d65009SMaciej S. Szmigiero .datareg = WB_SIO_GPIO12_REG_DATA1, 261*a0d65009SMaciej S. Szmigiero .conflict = { 262*a0d65009SMaciej S. Szmigiero .name = "UARTB", 263*a0d65009SMaciej S. Szmigiero .dev = WB_SIO_DEV_UARTB, 264*a0d65009SMaciej S. Szmigiero .testreg = WB_SIO_UARTB_REG_ENABLE, 265*a0d65009SMaciej S. Szmigiero .testbit = WB_SIO_UARTB_ENABLE_ON, 266*a0d65009SMaciej S. Szmigiero .warnonly = true 267*a0d65009SMaciej S. Szmigiero } 268*a0d65009SMaciej S. Szmigiero }, 269*a0d65009SMaciej S. Szmigiero { /* 1 */ 270*a0d65009SMaciej S. Szmigiero .dev = WB_SIO_DEV_GPIO12, 271*a0d65009SMaciej S. Szmigiero .enablereg = WB_SIO_GPIO12_REG_ENABLE, 272*a0d65009SMaciej S. Szmigiero .enablebit = WB_SIO_GPIO12_ENABLE_2, 273*a0d65009SMaciej S. Szmigiero .outputreg = WB_SIO_REG_GPIO1_MF, 274*a0d65009SMaciej S. Szmigiero .outputppbit = WB_SIO_REG_G1MF_G2PP, 275*a0d65009SMaciej S. Szmigiero .ioreg = WB_SIO_GPIO12_REG_IO2, 276*a0d65009SMaciej S. Szmigiero .invreg = WB_SIO_GPIO12_REG_INV2, 277*a0d65009SMaciej S. Szmigiero .datareg = WB_SIO_GPIO12_REG_DATA2 278*a0d65009SMaciej S. Szmigiero /* special conflict handling so doesn't use conflict data */ 279*a0d65009SMaciej S. Szmigiero }, 280*a0d65009SMaciej S. Szmigiero { /* 2 */ 281*a0d65009SMaciej S. Szmigiero .dev = WB_SIO_DEV_GPIO34, 282*a0d65009SMaciej S. Szmigiero .enablereg = WB_SIO_GPIO34_REG_ENABLE, 283*a0d65009SMaciej S. Szmigiero .enablebit = WB_SIO_GPIO34_ENABLE_3, 284*a0d65009SMaciej S. Szmigiero .outputreg = WB_SIO_REG_OVTGPIO3456, 285*a0d65009SMaciej S. Szmigiero .outputppbit = WB_SIO_REG_OG3456_G3PP, 286*a0d65009SMaciej S. Szmigiero .ioreg = WB_SIO_GPIO34_REG_IO3, 287*a0d65009SMaciej S. Szmigiero .invreg = WB_SIO_GPIO34_REG_INV3, 288*a0d65009SMaciej S. Szmigiero .datareg = WB_SIO_GPIO34_REG_DATA3, 289*a0d65009SMaciej S. Szmigiero .conflict = { 290*a0d65009SMaciej S. Szmigiero .name = "UARTC", 291*a0d65009SMaciej S. Szmigiero .dev = WB_SIO_DEV_UARTC, 292*a0d65009SMaciej S. Szmigiero .testreg = WB_SIO_UARTC_REG_ENABLE, 293*a0d65009SMaciej S. Szmigiero .testbit = WB_SIO_UARTC_ENABLE_ON, 294*a0d65009SMaciej S. Szmigiero .warnonly = true 295*a0d65009SMaciej S. Szmigiero } 296*a0d65009SMaciej S. Szmigiero }, 297*a0d65009SMaciej S. Szmigiero { /* 3 */ 298*a0d65009SMaciej S. Szmigiero .dev = WB_SIO_DEV_GPIO34, 299*a0d65009SMaciej S. Szmigiero .enablereg = WB_SIO_GPIO34_REG_ENABLE, 300*a0d65009SMaciej S. Szmigiero .enablebit = WB_SIO_GPIO34_ENABLE_4, 301*a0d65009SMaciej S. Szmigiero .outputreg = WB_SIO_REG_OVTGPIO3456, 302*a0d65009SMaciej S. Szmigiero .outputppbit = WB_SIO_REG_OG3456_G4PP, 303*a0d65009SMaciej S. Szmigiero .ioreg = WB_SIO_GPIO34_REG_IO4, 304*a0d65009SMaciej S. Szmigiero .invreg = WB_SIO_GPIO34_REG_INV4, 305*a0d65009SMaciej S. Szmigiero .datareg = WB_SIO_GPIO34_REG_DATA4, 306*a0d65009SMaciej S. Szmigiero .conflict = { 307*a0d65009SMaciej S. Szmigiero .name = "UARTD", 308*a0d65009SMaciej S. Szmigiero .dev = WB_SIO_DEV_UARTD, 309*a0d65009SMaciej S. Szmigiero .testreg = WB_SIO_UARTD_REG_ENABLE, 310*a0d65009SMaciej S. Szmigiero .testbit = WB_SIO_UARTD_ENABLE_ON, 311*a0d65009SMaciej S. Szmigiero .warnonly = true 312*a0d65009SMaciej S. Szmigiero } 313*a0d65009SMaciej S. Szmigiero }, 314*a0d65009SMaciej S. Szmigiero { /* 4 */ 315*a0d65009SMaciej S. Szmigiero .dev = WB_SIO_DEV_WDGPIO56, 316*a0d65009SMaciej S. Szmigiero .enablereg = WB_SIO_WDGPIO56_REG_ENABLE, 317*a0d65009SMaciej S. Szmigiero .enablebit = WB_SIO_WDGPIO56_ENABLE_5, 318*a0d65009SMaciej S. Szmigiero .outputreg = WB_SIO_REG_OVTGPIO3456, 319*a0d65009SMaciej S. Szmigiero .outputppbit = WB_SIO_REG_OG3456_G5PP, 320*a0d65009SMaciej S. Szmigiero .ioreg = WB_SIO_WDGPIO56_REG_IO5, 321*a0d65009SMaciej S. Szmigiero .invreg = WB_SIO_WDGPIO56_REG_INV5, 322*a0d65009SMaciej S. Szmigiero .datareg = WB_SIO_WDGPIO56_REG_DATA5, 323*a0d65009SMaciej S. Szmigiero .conflict = { 324*a0d65009SMaciej S. Szmigiero .name = "UARTE", 325*a0d65009SMaciej S. Szmigiero .dev = WB_SIO_DEV_UARTE, 326*a0d65009SMaciej S. Szmigiero .testreg = WB_SIO_UARTE_REG_ENABLE, 327*a0d65009SMaciej S. Szmigiero .testbit = WB_SIO_UARTE_ENABLE_ON, 328*a0d65009SMaciej S. Szmigiero .warnonly = true 329*a0d65009SMaciej S. Szmigiero } 330*a0d65009SMaciej S. Szmigiero }, 331*a0d65009SMaciej S. Szmigiero { /* 5 */ 332*a0d65009SMaciej S. Szmigiero .dev = WB_SIO_DEV_WDGPIO56, 333*a0d65009SMaciej S. Szmigiero .enablereg = WB_SIO_WDGPIO56_REG_ENABLE, 334*a0d65009SMaciej S. Szmigiero .enablebit = WB_SIO_WDGPIO56_ENABLE_6, 335*a0d65009SMaciej S. Szmigiero .outputreg = WB_SIO_REG_OVTGPIO3456, 336*a0d65009SMaciej S. Szmigiero .outputppbit = WB_SIO_REG_OG3456_G6PP, 337*a0d65009SMaciej S. Szmigiero .ioreg = WB_SIO_WDGPIO56_REG_IO6, 338*a0d65009SMaciej S. Szmigiero .invreg = WB_SIO_WDGPIO56_REG_INV6, 339*a0d65009SMaciej S. Szmigiero .datareg = WB_SIO_WDGPIO56_REG_DATA6, 340*a0d65009SMaciej S. Szmigiero .conflict = { 341*a0d65009SMaciej S. Szmigiero .name = "FDC", 342*a0d65009SMaciej S. Szmigiero .dev = WB_SIO_DEV_NONE, 343*a0d65009SMaciej S. Szmigiero .testreg = WB_SIO_REG_GLOBAL_OPT, 344*a0d65009SMaciej S. Szmigiero .testbit = WB_SIO_REG_GO_ENFDC, 345*a0d65009SMaciej S. Szmigiero .warnonly = false 346*a0d65009SMaciej S. Szmigiero } 347*a0d65009SMaciej S. Szmigiero } 348*a0d65009SMaciej S. Szmigiero }; 349*a0d65009SMaciej S. Szmigiero 350*a0d65009SMaciej S. Szmigiero /* returns whether changing a pin is allowed */ 351*a0d65009SMaciej S. Szmigiero static bool winbond_gpio_get_info(unsigned int *gpio_num, 352*a0d65009SMaciej S. Szmigiero const struct winbond_gpio_info **info) 353*a0d65009SMaciej S. Szmigiero { 354*a0d65009SMaciej S. Szmigiero bool allow_changing = true; 355*a0d65009SMaciej S. Szmigiero unsigned long i; 356*a0d65009SMaciej S. Szmigiero 357*a0d65009SMaciej S. Szmigiero for_each_set_bit(i, ¶ms.gpios, BITS_PER_LONG) { 358*a0d65009SMaciej S. Szmigiero if (*gpio_num < 8) 359*a0d65009SMaciej S. Szmigiero break; 360*a0d65009SMaciej S. Szmigiero 361*a0d65009SMaciej S. Szmigiero *gpio_num -= 8; 362*a0d65009SMaciej S. Szmigiero } 363*a0d65009SMaciej S. Szmigiero 364*a0d65009SMaciej S. Szmigiero *info = &winbond_gpio_infos[i]; 365*a0d65009SMaciej S. Szmigiero 366*a0d65009SMaciej S. Szmigiero /* 367*a0d65009SMaciej S. Szmigiero * GPIO2 (the second port) shares some pins with a basic PC 368*a0d65009SMaciej S. Szmigiero * functionality, which is very likely controlled by the firmware. 369*a0d65009SMaciej S. Szmigiero * Don't allow changing these pins by default. 370*a0d65009SMaciej S. Szmigiero */ 371*a0d65009SMaciej S. Szmigiero if (i == 1) { 372*a0d65009SMaciej S. Szmigiero if (*gpio_num == 0 && !params.pledgpio) 373*a0d65009SMaciej S. Szmigiero allow_changing = false; 374*a0d65009SMaciej S. Szmigiero else if (*gpio_num == 1 && !params.beepgpio) 375*a0d65009SMaciej S. Szmigiero allow_changing = false; 376*a0d65009SMaciej S. Szmigiero else if ((*gpio_num == 5 || *gpio_num == 6) && !params.i2cgpio) 377*a0d65009SMaciej S. Szmigiero allow_changing = false; 378*a0d65009SMaciej S. Szmigiero } 379*a0d65009SMaciej S. Szmigiero 380*a0d65009SMaciej S. Szmigiero return allow_changing; 381*a0d65009SMaciej S. Szmigiero } 382*a0d65009SMaciej S. Szmigiero 383*a0d65009SMaciej S. Szmigiero static int winbond_gpio_get(struct gpio_chip *gc, unsigned int offset) 384*a0d65009SMaciej S. Szmigiero { 385*a0d65009SMaciej S. Szmigiero unsigned long *base = gpiochip_get_data(gc); 386*a0d65009SMaciej S. Szmigiero const struct winbond_gpio_info *info; 387*a0d65009SMaciej S. Szmigiero bool val; 388*a0d65009SMaciej S. Szmigiero 389*a0d65009SMaciej S. Szmigiero winbond_gpio_get_info(&offset, &info); 390*a0d65009SMaciej S. Szmigiero 391*a0d65009SMaciej S. Szmigiero val = winbond_sio_enter(*base); 392*a0d65009SMaciej S. Szmigiero if (val) 393*a0d65009SMaciej S. Szmigiero return val; 394*a0d65009SMaciej S. Szmigiero 395*a0d65009SMaciej S. Szmigiero winbond_sio_select_logical(*base, info->dev); 396*a0d65009SMaciej S. Szmigiero 397*a0d65009SMaciej S. Szmigiero val = winbond_sio_reg_btest(*base, info->datareg, offset); 398*a0d65009SMaciej S. Szmigiero if (winbond_sio_reg_btest(*base, info->invreg, offset)) 399*a0d65009SMaciej S. Szmigiero val = !val; 400*a0d65009SMaciej S. Szmigiero 401*a0d65009SMaciej S. Szmigiero winbond_sio_leave(*base); 402*a0d65009SMaciej S. Szmigiero 403*a0d65009SMaciej S. Szmigiero return val; 404*a0d65009SMaciej S. Szmigiero } 405*a0d65009SMaciej S. Szmigiero 406*a0d65009SMaciej S. Szmigiero static int winbond_gpio_direction_in(struct gpio_chip *gc, unsigned int offset) 407*a0d65009SMaciej S. Szmigiero { 408*a0d65009SMaciej S. Szmigiero unsigned long *base = gpiochip_get_data(gc); 409*a0d65009SMaciej S. Szmigiero const struct winbond_gpio_info *info; 410*a0d65009SMaciej S. Szmigiero int ret; 411*a0d65009SMaciej S. Szmigiero 412*a0d65009SMaciej S. Szmigiero if (!winbond_gpio_get_info(&offset, &info)) 413*a0d65009SMaciej S. Szmigiero return -EACCES; 414*a0d65009SMaciej S. Szmigiero 415*a0d65009SMaciej S. Szmigiero ret = winbond_sio_enter(*base); 416*a0d65009SMaciej S. Szmigiero if (ret) 417*a0d65009SMaciej S. Szmigiero return ret; 418*a0d65009SMaciej S. Szmigiero 419*a0d65009SMaciej S. Szmigiero winbond_sio_select_logical(*base, info->dev); 420*a0d65009SMaciej S. Szmigiero 421*a0d65009SMaciej S. Szmigiero winbond_sio_reg_bset(*base, info->ioreg, offset); 422*a0d65009SMaciej S. Szmigiero 423*a0d65009SMaciej S. Szmigiero winbond_sio_leave(*base); 424*a0d65009SMaciej S. Szmigiero 425*a0d65009SMaciej S. Szmigiero return 0; 426*a0d65009SMaciej S. Szmigiero } 427*a0d65009SMaciej S. Szmigiero 428*a0d65009SMaciej S. Szmigiero static int winbond_gpio_direction_out(struct gpio_chip *gc, 429*a0d65009SMaciej S. Szmigiero unsigned int offset, 430*a0d65009SMaciej S. Szmigiero int val) 431*a0d65009SMaciej S. Szmigiero { 432*a0d65009SMaciej S. Szmigiero unsigned long *base = gpiochip_get_data(gc); 433*a0d65009SMaciej S. Szmigiero const struct winbond_gpio_info *info; 434*a0d65009SMaciej S. Szmigiero int ret; 435*a0d65009SMaciej S. Szmigiero 436*a0d65009SMaciej S. Szmigiero if (!winbond_gpio_get_info(&offset, &info)) 437*a0d65009SMaciej S. Szmigiero return -EACCES; 438*a0d65009SMaciej S. Szmigiero 439*a0d65009SMaciej S. Szmigiero ret = winbond_sio_enter(*base); 440*a0d65009SMaciej S. Szmigiero if (ret) 441*a0d65009SMaciej S. Szmigiero return ret; 442*a0d65009SMaciej S. Szmigiero 443*a0d65009SMaciej S. Szmigiero winbond_sio_select_logical(*base, info->dev); 444*a0d65009SMaciej S. Szmigiero 445*a0d65009SMaciej S. Szmigiero winbond_sio_reg_bclear(*base, info->ioreg, offset); 446*a0d65009SMaciej S. Szmigiero 447*a0d65009SMaciej S. Szmigiero if (winbond_sio_reg_btest(*base, info->invreg, offset)) 448*a0d65009SMaciej S. Szmigiero val = !val; 449*a0d65009SMaciej S. Szmigiero 450*a0d65009SMaciej S. Szmigiero if (val) 451*a0d65009SMaciej S. Szmigiero winbond_sio_reg_bset(*base, info->datareg, offset); 452*a0d65009SMaciej S. Szmigiero else 453*a0d65009SMaciej S. Szmigiero winbond_sio_reg_bclear(*base, info->datareg, offset); 454*a0d65009SMaciej S. Szmigiero 455*a0d65009SMaciej S. Szmigiero winbond_sio_leave(*base); 456*a0d65009SMaciej S. Szmigiero 457*a0d65009SMaciej S. Szmigiero return 0; 458*a0d65009SMaciej S. Szmigiero } 459*a0d65009SMaciej S. Szmigiero 460*a0d65009SMaciej S. Szmigiero static void winbond_gpio_set(struct gpio_chip *gc, unsigned int offset, 461*a0d65009SMaciej S. Szmigiero int val) 462*a0d65009SMaciej S. Szmigiero { 463*a0d65009SMaciej S. Szmigiero unsigned long *base = gpiochip_get_data(gc); 464*a0d65009SMaciej S. Szmigiero const struct winbond_gpio_info *info; 465*a0d65009SMaciej S. Szmigiero 466*a0d65009SMaciej S. Szmigiero if (!winbond_gpio_get_info(&offset, &info)) 467*a0d65009SMaciej S. Szmigiero return; 468*a0d65009SMaciej S. Szmigiero 469*a0d65009SMaciej S. Szmigiero if (winbond_sio_enter(*base) != 0) 470*a0d65009SMaciej S. Szmigiero return; 471*a0d65009SMaciej S. Szmigiero 472*a0d65009SMaciej S. Szmigiero winbond_sio_select_logical(*base, info->dev); 473*a0d65009SMaciej S. Szmigiero 474*a0d65009SMaciej S. Szmigiero if (winbond_sio_reg_btest(*base, info->invreg, offset)) 475*a0d65009SMaciej S. Szmigiero val = !val; 476*a0d65009SMaciej S. Szmigiero 477*a0d65009SMaciej S. Szmigiero if (val) 478*a0d65009SMaciej S. Szmigiero winbond_sio_reg_bset(*base, info->datareg, offset); 479*a0d65009SMaciej S. Szmigiero else 480*a0d65009SMaciej S. Szmigiero winbond_sio_reg_bclear(*base, info->datareg, offset); 481*a0d65009SMaciej S. Szmigiero 482*a0d65009SMaciej S. Szmigiero winbond_sio_leave(*base); 483*a0d65009SMaciej S. Szmigiero } 484*a0d65009SMaciej S. Szmigiero 485*a0d65009SMaciej S. Szmigiero static struct gpio_chip winbond_gpio_chip = { 486*a0d65009SMaciej S. Szmigiero .base = -1, 487*a0d65009SMaciej S. Szmigiero .label = WB_GPIO_DRIVER_NAME, 488*a0d65009SMaciej S. Szmigiero .owner = THIS_MODULE, 489*a0d65009SMaciej S. Szmigiero .can_sleep = true, 490*a0d65009SMaciej S. Szmigiero .get = winbond_gpio_get, 491*a0d65009SMaciej S. Szmigiero .direction_input = winbond_gpio_direction_in, 492*a0d65009SMaciej S. Szmigiero .set = winbond_gpio_set, 493*a0d65009SMaciej S. Szmigiero .direction_output = winbond_gpio_direction_out, 494*a0d65009SMaciej S. Szmigiero }; 495*a0d65009SMaciej S. Szmigiero 496*a0d65009SMaciej S. Szmigiero static void winbond_gpio_configure_port0_pins(unsigned long base) 497*a0d65009SMaciej S. Szmigiero { 498*a0d65009SMaciej S. Szmigiero unsigned int val; 499*a0d65009SMaciej S. Szmigiero 500*a0d65009SMaciej S. Szmigiero val = winbond_sio_reg_read(base, WB_SIO_REG_GPIO1_MF); 501*a0d65009SMaciej S. Szmigiero if ((val & WB_SIO_REG_G1MF_FS_MASK) == WB_SIO_REG_G1MF_FS_GPIO1) 502*a0d65009SMaciej S. Szmigiero return; 503*a0d65009SMaciej S. Szmigiero 504*a0d65009SMaciej S. Szmigiero pr_warn("GPIO1 pins were connected to something else (%.2x), fixing\n", 505*a0d65009SMaciej S. Szmigiero val); 506*a0d65009SMaciej S. Szmigiero 507*a0d65009SMaciej S. Szmigiero val &= ~WB_SIO_REG_G1MF_FS_MASK; 508*a0d65009SMaciej S. Szmigiero val |= WB_SIO_REG_G1MF_FS_GPIO1; 509*a0d65009SMaciej S. Szmigiero 510*a0d65009SMaciej S. Szmigiero winbond_sio_reg_write(base, WB_SIO_REG_GPIO1_MF, val); 511*a0d65009SMaciej S. Szmigiero } 512*a0d65009SMaciej S. Szmigiero 513*a0d65009SMaciej S. Szmigiero static void winbond_gpio_configure_port1_check_i2c(unsigned long base) 514*a0d65009SMaciej S. Szmigiero { 515*a0d65009SMaciej S. Szmigiero params.i2cgpio = !winbond_sio_reg_btest(base, WB_SIO_REG_I2C_PS, 516*a0d65009SMaciej S. Szmigiero WB_SIO_REG_I2CPS_I2CFS); 517*a0d65009SMaciej S. Szmigiero if (!params.i2cgpio) 518*a0d65009SMaciej S. Szmigiero pr_warn("disabling GPIO2.5 and GPIO2.6 as I2C is enabled\n"); 519*a0d65009SMaciej S. Szmigiero } 520*a0d65009SMaciej S. Szmigiero 521*a0d65009SMaciej S. Szmigiero static bool winbond_gpio_configure_port(unsigned long base, unsigned int idx) 522*a0d65009SMaciej S. Szmigiero { 523*a0d65009SMaciej S. Szmigiero const struct winbond_gpio_info *info = &winbond_gpio_infos[idx]; 524*a0d65009SMaciej S. Szmigiero const struct winbond_gpio_port_conflict *conflict = &info->conflict; 525*a0d65009SMaciej S. Szmigiero 526*a0d65009SMaciej S. Szmigiero /* is there a possible conflicting device defined? */ 527*a0d65009SMaciej S. Szmigiero if (conflict->name != NULL) { 528*a0d65009SMaciej S. Szmigiero if (conflict->dev != WB_SIO_DEV_NONE) 529*a0d65009SMaciej S. Szmigiero winbond_sio_select_logical(base, conflict->dev); 530*a0d65009SMaciej S. Szmigiero 531*a0d65009SMaciej S. Szmigiero if (winbond_sio_reg_btest(base, conflict->testreg, 532*a0d65009SMaciej S. Szmigiero conflict->testbit)) { 533*a0d65009SMaciej S. Szmigiero if (conflict->warnonly) 534*a0d65009SMaciej S. Szmigiero pr_warn("enabled GPIO%u share pins with active %s\n", 535*a0d65009SMaciej S. Szmigiero idx + 1, conflict->name); 536*a0d65009SMaciej S. Szmigiero else { 537*a0d65009SMaciej S. Szmigiero pr_warn("disabling GPIO%u as %s is enabled\n", 538*a0d65009SMaciej S. Szmigiero idx + 1, conflict->name); 539*a0d65009SMaciej S. Szmigiero return false; 540*a0d65009SMaciej S. Szmigiero } 541*a0d65009SMaciej S. Szmigiero } 542*a0d65009SMaciej S. Szmigiero } 543*a0d65009SMaciej S. Szmigiero 544*a0d65009SMaciej S. Szmigiero /* GPIO1 and GPIO2 need some (additional) special handling */ 545*a0d65009SMaciej S. Szmigiero if (idx == 0) 546*a0d65009SMaciej S. Szmigiero winbond_gpio_configure_port0_pins(base); 547*a0d65009SMaciej S. Szmigiero else if (idx == 1) 548*a0d65009SMaciej S. Szmigiero winbond_gpio_configure_port1_check_i2c(base); 549*a0d65009SMaciej S. Szmigiero 550*a0d65009SMaciej S. Szmigiero winbond_sio_select_logical(base, info->dev); 551*a0d65009SMaciej S. Szmigiero 552*a0d65009SMaciej S. Szmigiero winbond_sio_reg_bset(base, info->enablereg, info->enablebit); 553*a0d65009SMaciej S. Szmigiero 554*a0d65009SMaciej S. Szmigiero if (params.ppgpios & BIT(idx)) 555*a0d65009SMaciej S. Szmigiero winbond_sio_reg_bset(base, info->outputreg, 556*a0d65009SMaciej S. Szmigiero info->outputppbit); 557*a0d65009SMaciej S. Szmigiero else if (params.odgpios & BIT(idx)) 558*a0d65009SMaciej S. Szmigiero winbond_sio_reg_bclear(base, info->outputreg, 559*a0d65009SMaciej S. Szmigiero info->outputppbit); 560*a0d65009SMaciej S. Szmigiero else 561*a0d65009SMaciej S. Szmigiero pr_notice("GPIO%u pins are %s\n", idx + 1, 562*a0d65009SMaciej S. Szmigiero winbond_sio_reg_btest(base, info->outputreg, 563*a0d65009SMaciej S. Szmigiero info->outputppbit) ? 564*a0d65009SMaciej S. Szmigiero "push-pull" : 565*a0d65009SMaciej S. Szmigiero "open drain"); 566*a0d65009SMaciej S. Szmigiero 567*a0d65009SMaciej S. Szmigiero return true; 568*a0d65009SMaciej S. Szmigiero } 569*a0d65009SMaciej S. Szmigiero 570*a0d65009SMaciej S. Szmigiero static int winbond_gpio_configure(unsigned long base) 571*a0d65009SMaciej S. Szmigiero { 572*a0d65009SMaciej S. Szmigiero unsigned long i; 573*a0d65009SMaciej S. Szmigiero 574*a0d65009SMaciej S. Szmigiero for_each_set_bit(i, ¶ms.gpios, BITS_PER_LONG) 575*a0d65009SMaciej S. Szmigiero if (!winbond_gpio_configure_port(base, i)) 576*a0d65009SMaciej S. Szmigiero __clear_bit(i, ¶ms.gpios); 577*a0d65009SMaciej S. Szmigiero 578*a0d65009SMaciej S. Szmigiero if (!params.gpios) { 579*a0d65009SMaciej S. Szmigiero pr_err("please use 'gpios' module parameter to select some active GPIO ports to enable\n"); 580*a0d65009SMaciej S. Szmigiero return -EINVAL; 581*a0d65009SMaciej S. Szmigiero } 582*a0d65009SMaciej S. Szmigiero 583*a0d65009SMaciej S. Szmigiero return 0; 584*a0d65009SMaciej S. Szmigiero } 585*a0d65009SMaciej S. Szmigiero 586*a0d65009SMaciej S. Szmigiero static int winbond_gpio_check_chip(unsigned long base) 587*a0d65009SMaciej S. Szmigiero { 588*a0d65009SMaciej S. Szmigiero int ret; 589*a0d65009SMaciej S. Szmigiero unsigned int chip; 590*a0d65009SMaciej S. Szmigiero 591*a0d65009SMaciej S. Szmigiero ret = winbond_sio_enter(base); 592*a0d65009SMaciej S. Szmigiero if (ret) 593*a0d65009SMaciej S. Szmigiero return ret; 594*a0d65009SMaciej S. Szmigiero 595*a0d65009SMaciej S. Szmigiero chip = winbond_sio_reg_read(base, WB_SIO_REG_CHIP_MSB) << 8; 596*a0d65009SMaciej S. Szmigiero chip |= winbond_sio_reg_read(base, WB_SIO_REG_CHIP_LSB); 597*a0d65009SMaciej S. Szmigiero 598*a0d65009SMaciej S. Szmigiero pr_notice("chip ID at %lx is %.4x\n", base, chip); 599*a0d65009SMaciej S. Szmigiero 600*a0d65009SMaciej S. Szmigiero if ((chip & WB_SIO_CHIP_ID_W83627UHG_MASK) != 601*a0d65009SMaciej S. Szmigiero WB_SIO_CHIP_ID_W83627UHG) { 602*a0d65009SMaciej S. Szmigiero pr_err("not an our chip\n"); 603*a0d65009SMaciej S. Szmigiero ret = -ENODEV; 604*a0d65009SMaciej S. Szmigiero } 605*a0d65009SMaciej S. Szmigiero 606*a0d65009SMaciej S. Szmigiero winbond_sio_leave(base); 607*a0d65009SMaciej S. Szmigiero 608*a0d65009SMaciej S. Szmigiero return ret; 609*a0d65009SMaciej S. Szmigiero } 610*a0d65009SMaciej S. Szmigiero 611*a0d65009SMaciej S. Szmigiero static int winbond_gpio_imatch(struct device *dev, unsigned int id) 612*a0d65009SMaciej S. Szmigiero { 613*a0d65009SMaciej S. Szmigiero unsigned long gpios_rem; 614*a0d65009SMaciej S. Szmigiero int ret; 615*a0d65009SMaciej S. Szmigiero 616*a0d65009SMaciej S. Szmigiero gpios_rem = params.gpios & ~GENMASK(ARRAY_SIZE(winbond_gpio_infos) - 1, 617*a0d65009SMaciej S. Szmigiero 0); 618*a0d65009SMaciej S. Szmigiero if (gpios_rem) { 619*a0d65009SMaciej S. Szmigiero pr_warn("unknown ports (%lx) enabled in GPIO ports bitmask\n", 620*a0d65009SMaciej S. Szmigiero gpios_rem); 621*a0d65009SMaciej S. Szmigiero params.gpios &= ~gpios_rem; 622*a0d65009SMaciej S. Szmigiero } 623*a0d65009SMaciej S. Szmigiero 624*a0d65009SMaciej S. Szmigiero if (params.ppgpios & params.odgpios) { 625*a0d65009SMaciej S. Szmigiero pr_err("some GPIO ports are set both to push-pull and open drain mode at the same time\n"); 626*a0d65009SMaciej S. Szmigiero return 0; 627*a0d65009SMaciej S. Szmigiero } 628*a0d65009SMaciej S. Szmigiero 629*a0d65009SMaciej S. Szmigiero if (params.base != 0) 630*a0d65009SMaciej S. Szmigiero return winbond_gpio_check_chip(params.base) == 0; 631*a0d65009SMaciej S. Szmigiero 632*a0d65009SMaciej S. Szmigiero /* 633*a0d65009SMaciej S. Szmigiero * if the 'base' module parameter is unset probe two chip default 634*a0d65009SMaciej S. Szmigiero * I/O port bases 635*a0d65009SMaciej S. Szmigiero */ 636*a0d65009SMaciej S. Szmigiero params.base = WB_SIO_BASE; 637*a0d65009SMaciej S. Szmigiero ret = winbond_gpio_check_chip(params.base); 638*a0d65009SMaciej S. Szmigiero if (ret == 0) 639*a0d65009SMaciej S. Szmigiero return 1; 640*a0d65009SMaciej S. Szmigiero if (ret != -ENODEV && ret != -EBUSY) 641*a0d65009SMaciej S. Szmigiero return 0; 642*a0d65009SMaciej S. Szmigiero 643*a0d65009SMaciej S. Szmigiero params.base = WB_SIO_BASE_HIGH; 644*a0d65009SMaciej S. Szmigiero return winbond_gpio_check_chip(params.base) == 0; 645*a0d65009SMaciej S. Szmigiero } 646*a0d65009SMaciej S. Szmigiero 647*a0d65009SMaciej S. Szmigiero static int winbond_gpio_iprobe(struct device *dev, unsigned int id) 648*a0d65009SMaciej S. Szmigiero { 649*a0d65009SMaciej S. Szmigiero int ret; 650*a0d65009SMaciej S. Szmigiero 651*a0d65009SMaciej S. Szmigiero if (params.base == 0) 652*a0d65009SMaciej S. Szmigiero return -EINVAL; 653*a0d65009SMaciej S. Szmigiero 654*a0d65009SMaciej S. Szmigiero ret = winbond_sio_enter(params.base); 655*a0d65009SMaciej S. Szmigiero if (ret) 656*a0d65009SMaciej S. Szmigiero return ret; 657*a0d65009SMaciej S. Szmigiero 658*a0d65009SMaciej S. Szmigiero ret = winbond_gpio_configure(params.base); 659*a0d65009SMaciej S. Szmigiero 660*a0d65009SMaciej S. Szmigiero winbond_sio_leave(params.base); 661*a0d65009SMaciej S. Szmigiero 662*a0d65009SMaciej S. Szmigiero if (ret) 663*a0d65009SMaciej S. Szmigiero return ret; 664*a0d65009SMaciej S. Szmigiero 665*a0d65009SMaciej S. Szmigiero /* 666*a0d65009SMaciej S. Szmigiero * Add 8 gpios for every GPIO port that was enabled in gpios 667*a0d65009SMaciej S. Szmigiero * module parameter (that wasn't disabled earlier in 668*a0d65009SMaciej S. Szmigiero * winbond_gpio_configure() & co. due to, for example, a pin conflict). 669*a0d65009SMaciej S. Szmigiero */ 670*a0d65009SMaciej S. Szmigiero winbond_gpio_chip.ngpio = hweight_long(params.gpios) * 8; 671*a0d65009SMaciej S. Szmigiero 672*a0d65009SMaciej S. Szmigiero /* 673*a0d65009SMaciej S. Szmigiero * GPIO6 port has only 5 pins, so if it is enabled we have to adjust 674*a0d65009SMaciej S. Szmigiero * the total count appropriately 675*a0d65009SMaciej S. Szmigiero */ 676*a0d65009SMaciej S. Szmigiero if (params.gpios & BIT(5)) 677*a0d65009SMaciej S. Szmigiero winbond_gpio_chip.ngpio -= (8 - 5); 678*a0d65009SMaciej S. Szmigiero 679*a0d65009SMaciej S. Szmigiero winbond_gpio_chip.parent = dev; 680*a0d65009SMaciej S. Szmigiero 681*a0d65009SMaciej S. Szmigiero return devm_gpiochip_add_data(dev, &winbond_gpio_chip, ¶ms.base); 682*a0d65009SMaciej S. Szmigiero } 683*a0d65009SMaciej S. Szmigiero 684*a0d65009SMaciej S. Szmigiero static struct isa_driver winbond_gpio_idriver = { 685*a0d65009SMaciej S. Szmigiero .driver = { 686*a0d65009SMaciej S. Szmigiero .name = WB_GPIO_DRIVER_NAME, 687*a0d65009SMaciej S. Szmigiero }, 688*a0d65009SMaciej S. Szmigiero .match = winbond_gpio_imatch, 689*a0d65009SMaciej S. Szmigiero .probe = winbond_gpio_iprobe, 690*a0d65009SMaciej S. Szmigiero }; 691*a0d65009SMaciej S. Szmigiero 692*a0d65009SMaciej S. Szmigiero module_isa_driver(winbond_gpio_idriver, 1); 693*a0d65009SMaciej S. Szmigiero 694*a0d65009SMaciej S. Szmigiero module_param_named(base, params.base, ulong, 0444); 695*a0d65009SMaciej S. Szmigiero MODULE_PARM_DESC(base, 696*a0d65009SMaciej S. Szmigiero "I/O port base (when unset - probe chip default ones)"); 697*a0d65009SMaciej S. Szmigiero 698*a0d65009SMaciej S. Szmigiero /* This parameter sets which GPIO devices (ports) we enable */ 699*a0d65009SMaciej S. Szmigiero module_param_named(gpios, params.gpios, ulong, 0444); 700*a0d65009SMaciej S. Szmigiero MODULE_PARM_DESC(gpios, 701*a0d65009SMaciej S. Szmigiero "bitmask of GPIO ports to enable (bit 0 - GPIO1, bit 1 - GPIO2, etc."); 702*a0d65009SMaciej S. Szmigiero 703*a0d65009SMaciej S. Szmigiero /* 704*a0d65009SMaciej S. Szmigiero * These two parameters below set how we configure GPIO ports output drivers. 705*a0d65009SMaciej S. Szmigiero * It can't be a one bitmask since we need three values per port: push-pull, 706*a0d65009SMaciej S. Szmigiero * open-drain and keep as-is (this is the default). 707*a0d65009SMaciej S. Szmigiero */ 708*a0d65009SMaciej S. Szmigiero module_param_named(ppgpios, params.ppgpios, ulong, 0444); 709*a0d65009SMaciej S. Szmigiero MODULE_PARM_DESC(ppgpios, 710*a0d65009SMaciej S. Szmigiero "bitmask of GPIO ports to set to push-pull mode (bit 0 - GPIO1, bit 1 - GPIO2, etc."); 711*a0d65009SMaciej S. Szmigiero 712*a0d65009SMaciej S. Szmigiero module_param_named(odgpios, params.odgpios, ulong, 0444); 713*a0d65009SMaciej S. Szmigiero MODULE_PARM_DESC(odgpios, 714*a0d65009SMaciej S. Szmigiero "bitmask of GPIO ports to set to open drain mode (bit 0 - GPIO1, bit 1 - GPIO2, etc."); 715*a0d65009SMaciej S. Szmigiero 716*a0d65009SMaciej S. Szmigiero /* 717*a0d65009SMaciej S. Szmigiero * GPIO2.0 and GPIO2.1 control a basic PC functionality that we 718*a0d65009SMaciej S. Szmigiero * don't allow tinkering with by default (it is very likely that the 719*a0d65009SMaciej S. Szmigiero * firmware owns these pins). 720*a0d65009SMaciej S. Szmigiero * These two parameters below allow overriding these prohibitions. 721*a0d65009SMaciej S. Szmigiero */ 722*a0d65009SMaciej S. Szmigiero module_param_named(pledgpio, params.pledgpio, bool, 0644); 723*a0d65009SMaciej S. Szmigiero MODULE_PARM_DESC(pledgpio, 724*a0d65009SMaciej S. Szmigiero "enable changing value of GPIO2.0 bit (Power LED), default no."); 725*a0d65009SMaciej S. Szmigiero 726*a0d65009SMaciej S. Szmigiero module_param_named(beepgpio, params.beepgpio, bool, 0644); 727*a0d65009SMaciej S. Szmigiero MODULE_PARM_DESC(beepgpio, 728*a0d65009SMaciej S. Szmigiero "enable changing value of GPIO2.1 bit (BEEP), default no."); 729*a0d65009SMaciej S. Szmigiero 730*a0d65009SMaciej S. Szmigiero MODULE_AUTHOR("Maciej S. Szmigiero <mail@maciej.szmigiero.name>"); 731*a0d65009SMaciej S. Szmigiero MODULE_DESCRIPTION("GPIO interface for Winbond Super I/O chips"); 732*a0d65009SMaciej S. Szmigiero MODULE_LICENSE("GPL"); 733